blob: e1f173c2e519a92a047992762bd9d44ca93faeef [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
Jamie Madilld7b1ab52016-12-12 14:42:19 -050032const float kPi = 3.14159265358979323846f;
Arun Patole9dea48f2015-04-02 11:45:09 +053033const 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)
Jamie Madilld7b1ab52016-12-12 14:42:19 -050045 constUnion[i] = constant;
Arun Patole274f0702015-05-05 13:33:30 +053046
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",
Olli Etuaho4de340a2016-12-16 09:32:03 +000057 GetOperatorString(op));
Arun Patolebf790422015-05-18 17:53:04 +053058
59 switch (basicType)
60 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050061 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;
Arun Patolebf790422015-05-18 17:53:04 +053075 }
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.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500140 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530141 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
Jamie Madillb1a85f42014-08-19 15:23:24 -0400148////////////////////////////////////////////////////////////////
149//
150// Member functions of the nodes used for building the tree.
151//
152////////////////////////////////////////////////////////////////
153
Olli Etuahod2a67b92014-10-21 16:42:57 +0300154void TIntermTyped::setTypePreservePrecision(const TType &t)
155{
156 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500157 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300158 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
159 mType.setPrecision(precision);
160}
161
Jamie Madillb1a85f42014-08-19 15:23:24 -0400162#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500163 if (node == original) \
164 { \
165 node = static_cast<type *>(replacement); \
166 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400167 }
168
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500169bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400170{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300171 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400172 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
173 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
174 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100175 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400176 return false;
177}
178
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500179bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400180{
181 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
182 return false;
183}
184
Olli Etuahob6fa0432016-09-28 16:28:05 +0100185bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
186{
187 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
188 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
189 return false;
190}
191
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500192bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400193{
194 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
195 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
196 return false;
197}
198
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500199bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400200{
Olli Etuahoa2234302016-08-31 12:05:39 +0300201 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400202 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
203 return false;
204}
205
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000206bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
207{
208 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
209 return false;
210}
211
Olli Etuaho336b1472016-10-05 16:37:55 +0100212bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
213{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000214 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100215 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
216 return false;
217}
218
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500219bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400220{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100221 return replaceChildNodeInternal(original, replacement);
222}
223
224bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
225{
226 return replaceChildNodeInternal(original, replacement);
227}
228
Olli Etuaho16c745a2017-01-16 17:02:27 +0000229bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
230{
231 return replaceChildNodeInternal(original, replacement);
232}
233
Olli Etuaho13389b62016-10-16 11:48:18 +0100234bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
235{
236 return replaceChildNodeInternal(original, replacement);
237}
238
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100239bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
240{
241 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400242 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100243 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400244 }
245 return false;
246}
247
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100248bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
249 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300250{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100251 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300252 {
253 if (*it == original)
254 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100255 it = getSequence()->erase(it);
256 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300257 return true;
258 }
259 }
260 return false;
261}
262
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100263bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
264 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300265{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100266 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300267 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300268 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300269 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100270 auto it = getSequence()->begin() + position;
271 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300272 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300273}
274
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800275TIntermAggregate::TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments)
276 : TIntermOperator(op), mUseEmulatedFunction(false), mGotPrecisionFromChildren(false)
277{
278 if (arguments != nullptr)
279 {
280 mArguments.swap(*arguments);
281 }
282 setTypePrecisionAndQualifier(type);
283}
284
285void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
286{
287 setType(type);
288 mType.setQualifier(EvqTemporary);
289 if (!isFunctionCall())
290 {
291 if (isConstructor())
292 {
293 // Structs should not be precision qualified, the individual members may be.
294 // Built-in types on the other hand should be precision qualified.
295 if (mOp != EOpConstructStruct)
296 {
297 setPrecisionFromChildren();
298 }
299 }
300 else
301 {
302 setPrecisionForBuiltInOp();
303 }
304 if (areChildrenConstQualified())
305 {
306 mType.setQualifier(EvqConst);
307 }
308 }
309}
310
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200311bool TIntermAggregate::areChildrenConstQualified()
312{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800313 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200314 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800315 TIntermTyped *typedArg = arg->getAsTyped();
316 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200317 {
318 return false;
319 }
320 }
321 return true;
322}
323
Olli Etuahod2a67b92014-10-21 16:42:57 +0300324void TIntermAggregate::setPrecisionFromChildren()
325{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300326 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300327 if (getBasicType() == EbtBool)
328 {
329 mType.setPrecision(EbpUndefined);
330 return;
331 }
332
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500333 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800334 TIntermSequence::iterator childIter = mArguments.begin();
335 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300336 {
337 TIntermTyped *typed = (*childIter)->getAsTyped();
338 if (typed)
339 precision = GetHigherPrecision(typed->getPrecision(), precision);
340 ++childIter;
341 }
342 mType.setPrecision(precision);
343}
344
Olli Etuaho9250cb22017-01-21 10:51:27 +0000345void TIntermAggregate::setPrecisionForBuiltInOp()
346{
347 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800348 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000349 if (!setPrecisionForSpecialBuiltInOp())
350 {
351 setPrecisionFromChildren();
352 }
353}
354
355bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
356{
357 switch (mOp)
358 {
359 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800360 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
361 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000362 return true;
363 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800364 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
365 mArguments[1]->getAsTyped()->getPrecision()));
366 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000367 return true;
368 case EOpUaddCarry:
369 case EOpUsubBorrow:
370 mType.setPrecision(EbpHigh);
371 return true;
372 default:
373 return false;
374 }
375}
376
Olli Etuahod2a67b92014-10-21 16:42:57 +0300377void TIntermAggregate::setBuiltInFunctionPrecision()
378{
379 // All built-ins returning bool should be handled as ops, not functions.
380 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800381 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300382
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800383 TPrecision precision = EbpUndefined;
384 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300385 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800386 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300387 // ESSL spec section 8: texture functions get their precision from the sampler.
388 if (typed && IsSampler(typed->getBasicType()))
389 {
390 precision = typed->getPrecision();
391 break;
392 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300393 }
394 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
395 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100396 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300397 mType.setPrecision(EbpHigh);
398 else
399 mType.setPrecision(precision);
400}
401
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100402void TIntermBlock::appendStatement(TIntermNode *statement)
403{
Olli Etuaho13389b62016-10-16 11:48:18 +0100404 // Declaration nodes with no children can appear if all the declarators just added constants to
405 // the symbol table instead of generating code. They're no-ops so they aren't added to blocks.
406 if (statement != nullptr && (statement->getAsDeclarationNode() == nullptr ||
407 !statement->getAsDeclarationNode()->getSequence()->empty()))
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100408 {
409 mStatements.push_back(statement);
410 }
411}
412
Olli Etuaho16c745a2017-01-16 17:02:27 +0000413void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
414{
415 ASSERT(parameter != nullptr);
416 mParameters.push_back(parameter);
417}
418
Olli Etuaho13389b62016-10-16 11:48:18 +0100419void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
420{
421 ASSERT(declarator != nullptr);
422 ASSERT(declarator->getAsSymbolNode() != nullptr ||
423 (declarator->getAsBinaryNode() != nullptr &&
424 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
425 ASSERT(mDeclarators.empty() ||
426 declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType()));
427 mDeclarators.push_back(declarator);
428}
429
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300430bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
431{
432 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
433 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
434 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
435 return false;
436}
437
Olli Etuaho57961272016-09-14 13:57:46 +0300438bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400439{
440 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100441 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
442 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400443 return false;
444}
445
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500446bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200447{
448 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100449 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200450 return false;
451}
452
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500453bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200454{
455 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
456 return false;
457}
458
Olli Etuahod7a25242015-08-18 13:49:45 +0300459TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
460{
461 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
462 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
463 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
464 mLine = node.mLine;
465}
466
Olli Etuahod4f4c112016-04-15 15:11:24 +0300467bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
468{
469 TIntermAggregate *constructor = getAsAggregate();
470 if (!constructor || !constructor->isConstructor())
471 {
472 return false;
473 }
474 for (TIntermNode *&node : *constructor->getSequence())
475 {
476 if (!node->getAsConstantUnion())
477 return false;
478 }
479 return true;
480}
481
Corentin Wallez509e4562016-08-25 14:55:44 -0400482// static
483TIntermTyped *TIntermTyped::CreateIndexNode(int index)
484{
485 TConstantUnion *u = new TConstantUnion[1];
486 u[0].setIConst(index);
487
488 TType type(EbtInt, EbpUndefined, EvqConst, 1);
489 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
490 return node;
491}
492
493// static
494TIntermTyped *TIntermTyped::CreateZero(const TType &type)
495{
496 TType constType(type);
497 constType.setQualifier(EvqConst);
498
499 if (!type.isArray() && type.getBasicType() != EbtStruct)
500 {
501 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
502
503 size_t size = constType.getObjectSize();
504 TConstantUnion *u = new TConstantUnion[size];
505 for (size_t i = 0; i < size; ++i)
506 {
507 switch (type.getBasicType())
508 {
509 case EbtFloat:
510 u[i].setFConst(0.0f);
511 break;
512 case EbtInt:
513 u[i].setIConst(0);
514 break;
515 case EbtUInt:
516 u[i].setUConst(0u);
517 break;
518 case EbtBool:
519 u[i].setBConst(false);
520 break;
521 default:
Corentin Wallez17a5c062017-01-22 15:20:53 -0500522 // CreateZero is called by ParseContext that keeps parsing even when an error
523 // occurs, so it is possible for CreateZero to be called with non-basic types.
524 // This happens only on error condition but CreateZero needs to return a value
525 // with the correct type to continue the typecheck. That's why we handle
526 // non-basic type by setting whatever value, we just need the type to be right.
527 u[i].setIConst(42);
528 break;
Corentin Wallez509e4562016-08-25 14:55:44 -0400529 }
530 }
531
532 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
533 return node;
534 }
535
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800536 TIntermSequence *arguments = new TIntermSequence();
Corentin Wallez509e4562016-08-25 14:55:44 -0400537
538 if (type.isArray())
539 {
540 TType elementType(type);
541 elementType.clearArrayness();
542
543 size_t arraySize = type.getArraySize();
544 for (size_t i = 0; i < arraySize; ++i)
545 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800546 arguments->push_back(CreateZero(elementType));
Corentin Wallez509e4562016-08-25 14:55:44 -0400547 }
548 }
549 else
550 {
551 ASSERT(type.getBasicType() == EbtStruct);
552
553 TStructure *structure = type.getStruct();
554 for (const auto &field : structure->fields())
555 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800556 arguments->push_back(CreateZero(*field->type()));
Corentin Wallez509e4562016-08-25 14:55:44 -0400557 }
558 }
559
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800560 return new TIntermAggregate(constType, sh::TypeToConstructorOperator(type), arguments);
Corentin Wallez509e4562016-08-25 14:55:44 -0400561}
562
Corentin Wallez36fd1002016-12-08 11:30:44 -0500563// static
564TIntermTyped *TIntermTyped::CreateBool(bool value)
565{
566 TConstantUnion *u = new TConstantUnion[1];
567 u[0].setBConst(value);
568
569 TType type(EbtBool, EbpUndefined, EvqConst, 1);
570 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
571 return node;
572}
573
Olli Etuahod7a25242015-08-18 13:49:45 +0300574TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
575{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200576 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300577}
578
Olli Etuahobd674552016-10-06 13:28:42 +0100579void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
580{
581 setName(function.getMangledName());
582 setId(function.getUniqueId());
583}
584
Olli Etuahod7a25242015-08-18 13:49:45 +0300585TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
586 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300587 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100588 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
589 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300590{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800591 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300592 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800593 TIntermTyped *typedArg = arg->getAsTyped();
594 ASSERT(typedArg != nullptr);
595 TIntermTyped *argCopy = typedArg->deepCopy();
596 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300597 }
598}
599
Olli Etuahob6fa0432016-09-28 16:28:05 +0100600TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
601{
602 TIntermTyped *operandCopy = node.mOperand->deepCopy();
603 ASSERT(operandCopy != nullptr);
604 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000605 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100606}
607
Olli Etuahod7a25242015-08-18 13:49:45 +0300608TIntermBinary::TIntermBinary(const TIntermBinary &node)
609 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
610{
611 TIntermTyped *leftCopy = node.mLeft->deepCopy();
612 TIntermTyped *rightCopy = node.mRight->deepCopy();
613 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
614 mLeft = leftCopy;
615 mRight = rightCopy;
616}
617
618TIntermUnary::TIntermUnary(const TIntermUnary &node)
619 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
620{
621 TIntermTyped *operandCopy = node.mOperand->deepCopy();
622 ASSERT(operandCopy != nullptr);
623 mOperand = operandCopy;
624}
625
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300626TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300627{
Olli Etuahod7a25242015-08-18 13:49:45 +0300628 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300629 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
630 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300631 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300632 mCondition = conditionCopy;
633 mTrueExpression = trueCopy;
634 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300635}
636
Jamie Madillb1a85f42014-08-19 15:23:24 -0400637bool TIntermOperator::isAssignment() const
638{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300639 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400640}
641
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300642bool TIntermOperator::isMultiplication() const
643{
644 switch (mOp)
645 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500646 case EOpMul:
647 case EOpMatrixTimesMatrix:
648 case EOpMatrixTimesVector:
649 case EOpMatrixTimesScalar:
650 case EOpVectorTimesMatrix:
651 case EOpVectorTimesScalar:
652 return true;
653 default:
654 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300655 }
656}
657
Jamie Madillb1a85f42014-08-19 15:23:24 -0400658//
659// returns true if the operator is for one of the constructors
660//
661bool TIntermOperator::isConstructor() const
662{
663 switch (mOp)
664 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500665 case EOpConstructVec2:
666 case EOpConstructVec3:
667 case EOpConstructVec4:
668 case EOpConstructMat2:
669 case EOpConstructMat2x3:
670 case EOpConstructMat2x4:
671 case EOpConstructMat3x2:
672 case EOpConstructMat3:
673 case EOpConstructMat3x4:
674 case EOpConstructMat4x2:
675 case EOpConstructMat4x3:
676 case EOpConstructMat4:
677 case EOpConstructFloat:
678 case EOpConstructIVec2:
679 case EOpConstructIVec3:
680 case EOpConstructIVec4:
681 case EOpConstructInt:
682 case EOpConstructUVec2:
683 case EOpConstructUVec3:
684 case EOpConstructUVec4:
685 case EOpConstructUInt:
686 case EOpConstructBVec2:
687 case EOpConstructBVec3:
688 case EOpConstructBVec4:
689 case EOpConstructBool:
690 case EOpConstructStruct:
691 return true;
692 default:
693 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400694 }
695}
696
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800697bool TIntermOperator::isFunctionCall() const
698{
699 switch (mOp)
700 {
701 case EOpCallFunctionInAST:
702 case EOpCallBuiltInFunction:
703 case EOpCallInternalRawFunction:
704 return true;
705 default:
706 return false;
707 }
708}
709
Olli Etuaho1dded802016-08-18 18:13:13 +0300710TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
711{
712 if (left.isMatrix())
713 {
714 if (right.isMatrix())
715 {
716 return EOpMatrixTimesMatrix;
717 }
718 else
719 {
720 if (right.isVector())
721 {
722 return EOpMatrixTimesVector;
723 }
724 else
725 {
726 return EOpMatrixTimesScalar;
727 }
728 }
729 }
730 else
731 {
732 if (right.isMatrix())
733 {
734 if (left.isVector())
735 {
736 return EOpVectorTimesMatrix;
737 }
738 else
739 {
740 return EOpMatrixTimesScalar;
741 }
742 }
743 else
744 {
745 // Neither operand is a matrix.
746 if (left.isVector() == right.isVector())
747 {
748 // Leave as component product.
749 return EOpMul;
750 }
751 else
752 {
753 return EOpVectorTimesScalar;
754 }
755 }
756 }
757}
758
759TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
760{
761 if (left.isMatrix())
762 {
763 if (right.isMatrix())
764 {
765 return EOpMatrixTimesMatrixAssign;
766 }
767 else
768 {
769 // right should be scalar, but this may not be validated yet.
770 return EOpMatrixTimesScalarAssign;
771 }
772 }
773 else
774 {
775 if (right.isMatrix())
776 {
777 // Left should be a vector, but this may not be validated yet.
778 return EOpVectorTimesMatrixAssign;
779 }
780 else
781 {
782 // Neither operand is a matrix.
783 if (left.isVector() == right.isVector())
784 {
785 // Leave as component product.
786 return EOpMulAssign;
787 }
788 else
789 {
790 // left should be vector and right should be scalar, but this may not be validated
791 // yet.
792 return EOpVectorTimesScalarAssign;
793 }
794 }
795 }
796}
797
Jamie Madillb1a85f42014-08-19 15:23:24 -0400798//
799// Make sure the type of a unary operator is appropriate for its
800// combination of operation and operand type.
801//
Olli Etuahoa2234302016-08-31 12:05:39 +0300802void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400803{
Olli Etuahoa2234302016-08-31 12:05:39 +0300804 TQualifier resultQualifier = EvqTemporary;
805 if (mOperand->getQualifier() == EvqConst)
806 resultQualifier = EvqConst;
807
808 unsigned char operandPrimarySize =
809 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400810 switch (mOp)
811 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300812 case EOpFloatBitsToInt:
813 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
814 break;
815 case EOpFloatBitsToUint:
816 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
817 break;
818 case EOpIntBitsToFloat:
819 case EOpUintBitsToFloat:
820 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
821 break;
822 case EOpPackSnorm2x16:
823 case EOpPackUnorm2x16:
824 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800825 case EOpPackUnorm4x8:
826 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300827 setType(TType(EbtUInt, EbpHigh, resultQualifier));
828 break;
829 case EOpUnpackSnorm2x16:
830 case EOpUnpackUnorm2x16:
831 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
832 break;
833 case EOpUnpackHalf2x16:
834 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
835 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800836 case EOpUnpackUnorm4x8:
837 case EOpUnpackSnorm4x8:
838 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
839 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300840 case EOpAny:
841 case EOpAll:
842 setType(TType(EbtBool, EbpUndefined, resultQualifier));
843 break;
844 case EOpLength:
845 case EOpDeterminant:
846 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
847 break;
848 case EOpTranspose:
849 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
850 static_cast<unsigned char>(mOperand->getType().getRows()),
851 static_cast<unsigned char>(mOperand->getType().getCols())));
852 break;
853 case EOpIsInf:
854 case EOpIsNan:
855 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
856 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000857 case EOpBitfieldReverse:
858 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
859 break;
860 case EOpBitCount:
861 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
862 break;
863 case EOpFindLSB:
864 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
865 break;
866 case EOpFindMSB:
867 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
868 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300869 default:
870 setType(mOperand->getType());
871 mType.setQualifier(resultQualifier);
872 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400873 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300874}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400875
Olli Etuahob6fa0432016-09-28 16:28:05 +0100876TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
877 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
878 mOperand(operand),
879 mSwizzleOffsets(swizzleOffsets)
880{
881 ASSERT(mSwizzleOffsets.size() <= 4);
882 promote();
883}
884
Olli Etuahoa2234302016-08-31 12:05:39 +0300885TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
886 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
887{
888 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400889}
890
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300891TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
892 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
893{
894 promote();
895}
896
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000897TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
898 : TIntermNode(), mSymbol(symbol)
899{
900 ASSERT(symbol);
901 setLine(line);
902}
903
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300904TIntermTernary::TIntermTernary(TIntermTyped *cond,
905 TIntermTyped *trueExpression,
906 TIntermTyped *falseExpression)
907 : TIntermTyped(trueExpression->getType()),
908 mCondition(cond),
909 mTrueExpression(trueExpression),
910 mFalseExpression(falseExpression)
911{
912 getTypePointer()->setQualifier(
913 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
914}
915
916// static
917TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
918 TIntermTyped *trueExpression,
919 TIntermTyped *falseExpression)
920{
921 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
922 falseExpression->getQualifier() == EvqConst)
923 {
924 return EvqConst;
925 }
926 return EvqTemporary;
927}
928
Olli Etuahob6fa0432016-09-28 16:28:05 +0100929void TIntermSwizzle::promote()
930{
931 TQualifier resultQualifier = EvqTemporary;
932 if (mOperand->getQualifier() == EvqConst)
933 resultQualifier = EvqConst;
934
935 auto numFields = mSwizzleOffsets.size();
936 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
937 static_cast<unsigned char>(numFields)));
938}
939
940bool TIntermSwizzle::hasDuplicateOffsets() const
941{
942 int offsetCount[4] = {0u, 0u, 0u, 0u};
943 for (const auto offset : mSwizzleOffsets)
944 {
945 offsetCount[offset]++;
946 if (offsetCount[offset] > 1)
947 {
948 return true;
949 }
950 }
951 return false;
952}
953
Olli Etuaho09b04a22016-12-15 13:30:26 +0000954bool TIntermSwizzle::offsetsMatch(int offset) const
955{
956 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
957}
958
Olli Etuahob6fa0432016-09-28 16:28:05 +0100959void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
960{
961 for (const int offset : mSwizzleOffsets)
962 {
963 switch (offset)
964 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500965 case 0:
966 *out << "x";
967 break;
968 case 1:
969 *out << "y";
970 break;
971 case 2:
972 *out << "z";
973 break;
974 case 3:
975 *out << "w";
976 break;
977 default:
978 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +0100979 }
980 }
981}
982
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100983TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
984 const TIntermTyped *left,
985 const TIntermTyped *right)
986{
987 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
988 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
989 right->getQualifier() != EvqConst)
990 {
991 return EvqTemporary;
992 }
993 return EvqConst;
994}
Olli Etuahob6fa0432016-09-28 16:28:05 +0100995
996// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300997void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400998{
Olli Etuaho1dded802016-08-18 18:13:13 +0300999 ASSERT(!isMultiplication() ||
1000 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1001
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001002 // Comma is handled as a special case.
1003 if (mOp == EOpComma)
1004 {
1005 setType(mRight->getType());
1006 return;
1007 }
1008
Jamie Madillb1a85f42014-08-19 15:23:24 -04001009 // Base assumption: just make the type the same as the left
1010 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001011 setType(mLeft->getType());
1012
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001013 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001014 // Binary operations results in temporary variables unless both
1015 // operands are const.
1016 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1017 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001018 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001019 getTypePointer()->setQualifier(EvqTemporary);
1020 }
1021
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001022 // Handle indexing ops.
1023 switch (mOp)
1024 {
1025 case EOpIndexDirect:
1026 case EOpIndexIndirect:
1027 if (mLeft->isArray())
1028 {
1029 mType.clearArrayness();
1030 }
1031 else if (mLeft->isMatrix())
1032 {
1033 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1034 static_cast<unsigned char>(mLeft->getRows())));
1035 }
1036 else if (mLeft->isVector())
1037 {
1038 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1039 }
1040 else
1041 {
1042 UNREACHABLE();
1043 }
1044 return;
1045 case EOpIndexDirectStruct:
1046 {
1047 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1048 const int i = mRight->getAsConstantUnion()->getIConst(0);
1049 setType(*fields[i]->type());
1050 getTypePointer()->setQualifier(resultQualifier);
1051 return;
1052 }
1053 case EOpIndexDirectInterfaceBlock:
1054 {
1055 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1056 const int i = mRight->getAsConstantUnion()->getIConst(0);
1057 setType(*fields[i]->type());
1058 getTypePointer()->setQualifier(resultQualifier);
1059 return;
1060 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001061 default:
1062 break;
1063 }
1064
1065 ASSERT(mLeft->isArray() == mRight->isArray());
1066
1067 // The result gets promoted to the highest precision.
1068 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1069 getTypePointer()->setPrecision(higherPrecision);
1070
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001071 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001072
1073 //
1074 // All scalars or structs. Code after this test assumes this case is removed!
1075 //
1076 if (nominalSize == 1)
1077 {
1078 switch (mOp)
1079 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001080 //
1081 // Promote to conditional
1082 //
1083 case EOpEqual:
1084 case EOpNotEqual:
1085 case EOpLessThan:
1086 case EOpGreaterThan:
1087 case EOpLessThanEqual:
1088 case EOpGreaterThanEqual:
1089 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1090 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001091
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001092 //
1093 // And and Or operate on conditionals
1094 //
1095 case EOpLogicalAnd:
1096 case EOpLogicalXor:
1097 case EOpLogicalOr:
1098 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1099 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1100 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001101
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001102 default:
1103 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001104 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001105 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001106 }
1107
1108 // If we reach here, at least one of the operands is vector or matrix.
1109 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001110 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001111
Jamie Madillb1a85f42014-08-19 15:23:24 -04001112 switch (mOp)
1113 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001114 case EOpMul:
1115 break;
1116 case EOpMatrixTimesScalar:
1117 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001118 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001119 setType(TType(basicType, higherPrecision, resultQualifier,
1120 static_cast<unsigned char>(mRight->getCols()),
1121 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001122 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001123 break;
1124 case EOpMatrixTimesVector:
1125 setType(TType(basicType, higherPrecision, resultQualifier,
1126 static_cast<unsigned char>(mLeft->getRows()), 1));
1127 break;
1128 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001129 setType(TType(basicType, higherPrecision, resultQualifier,
1130 static_cast<unsigned char>(mRight->getCols()),
1131 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001132 break;
1133 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001134 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001135 static_cast<unsigned char>(nominalSize), 1));
1136 break;
1137 case EOpVectorTimesMatrix:
1138 setType(TType(basicType, higherPrecision, resultQualifier,
1139 static_cast<unsigned char>(mRight->getCols()), 1));
1140 break;
1141 case EOpMulAssign:
1142 case EOpVectorTimesScalarAssign:
1143 case EOpVectorTimesMatrixAssign:
1144 case EOpMatrixTimesScalarAssign:
1145 case EOpMatrixTimesMatrixAssign:
1146 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1147 break;
1148 case EOpAssign:
1149 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001150 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1151 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1152 break;
1153 case EOpAdd:
1154 case EOpSub:
1155 case EOpDiv:
1156 case EOpIMod:
1157 case EOpBitShiftLeft:
1158 case EOpBitShiftRight:
1159 case EOpBitwiseAnd:
1160 case EOpBitwiseXor:
1161 case EOpBitwiseOr:
1162 case EOpAddAssign:
1163 case EOpSubAssign:
1164 case EOpDivAssign:
1165 case EOpIModAssign:
1166 case EOpBitShiftLeftAssign:
1167 case EOpBitShiftRightAssign:
1168 case EOpBitwiseAndAssign:
1169 case EOpBitwiseXorAssign:
1170 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001171 {
1172 const int secondarySize =
1173 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1174 setType(TType(basicType, higherPrecision, resultQualifier,
1175 static_cast<unsigned char>(nominalSize),
1176 static_cast<unsigned char>(secondarySize)));
1177 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001178 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001179 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001180 case EOpEqual:
1181 case EOpNotEqual:
1182 case EOpLessThan:
1183 case EOpGreaterThan:
1184 case EOpLessThanEqual:
1185 case EOpGreaterThanEqual:
1186 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1187 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001188 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001189 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001190
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001191 case EOpIndexDirect:
1192 case EOpIndexIndirect:
1193 case EOpIndexDirectInterfaceBlock:
1194 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001195 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001196 UNREACHABLE();
1197 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001198 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001199 UNREACHABLE();
1200 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001201 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001202}
1203
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001204const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001205{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001206 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001207 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001208 ASSERT(index < static_cast<int>(getType().getArraySize()));
1209 TType arrayElementType = getType();
1210 arrayElementType.clearArrayness();
1211 size_t arrayElementSize = arrayElementType.getObjectSize();
1212 return &mUnionArrayPointer[arrayElementSize * index];
1213 }
1214 else if (isMatrix())
1215 {
1216 ASSERT(index < getType().getCols());
1217 int size = getType().getRows();
1218 return &mUnionArrayPointer[size * index];
1219 }
1220 else if (isVector())
1221 {
1222 ASSERT(index < getType().getNominalSize());
1223 return &mUnionArrayPointer[index];
1224 }
1225 else
1226 {
1227 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001228 return nullptr;
1229 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001230}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001231
Olli Etuahob6fa0432016-09-28 16:28:05 +01001232TIntermTyped *TIntermSwizzle::fold()
1233{
1234 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1235 if (operandConstant == nullptr)
1236 {
1237 return nullptr;
1238 }
1239
1240 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1241 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1242 {
1243 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1244 }
1245 return CreateFoldedNode(constArray, this, mType.getQualifier());
1246}
1247
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001248TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1249{
1250 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1251 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1252 switch (mOp)
1253 {
1254 case EOpIndexDirect:
1255 {
1256 if (leftConstant == nullptr || rightConstant == nullptr)
1257 {
1258 return nullptr;
1259 }
1260 int index = rightConstant->getIConst(0);
1261
1262 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1263 return CreateFoldedNode(constArray, this, mType.getQualifier());
1264 }
1265 case EOpIndexDirectStruct:
1266 {
1267 if (leftConstant == nullptr || rightConstant == nullptr)
1268 {
1269 return nullptr;
1270 }
1271 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1272 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1273
1274 size_t previousFieldsSize = 0;
1275 for (size_t i = 0; i < index; ++i)
1276 {
1277 previousFieldsSize += fields[i]->type()->getObjectSize();
1278 }
1279
1280 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1281 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1282 }
1283 case EOpIndexIndirect:
1284 case EOpIndexDirectInterfaceBlock:
1285 // Can never be constant folded.
1286 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001287 default:
1288 {
1289 if (leftConstant == nullptr || rightConstant == nullptr)
1290 {
1291 return nullptr;
1292 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001293 TConstantUnion *constArray =
1294 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001295
1296 // Nodes may be constant folded without being qualified as constant.
1297 return CreateFoldedNode(constArray, this, mType.getQualifier());
1298 }
1299 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001300}
1301
Olli Etuahof119a262016-08-19 15:54:22 +03001302TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001303{
1304 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1305 if (operandConstant == nullptr)
1306 {
1307 return nullptr;
1308 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301309
1310 TConstantUnion *constArray = nullptr;
1311 switch (mOp)
1312 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001313 case EOpAny:
1314 case EOpAll:
1315 case EOpLength:
1316 case EOpTranspose:
1317 case EOpDeterminant:
1318 case EOpInverse:
1319 case EOpPackSnorm2x16:
1320 case EOpUnpackSnorm2x16:
1321 case EOpPackUnorm2x16:
1322 case EOpUnpackUnorm2x16:
1323 case EOpPackHalf2x16:
1324 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001325 case EOpPackUnorm4x8:
1326 case EOpPackSnorm4x8:
1327 case EOpUnpackUnorm4x8:
1328 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001329 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1330 break;
1331 default:
1332 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1333 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301334 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001335
1336 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001337 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001338}
1339
Olli Etuahof119a262016-08-19 15:54:22 +03001340TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001341{
1342 // Make sure that all params are constant before actual constant folding.
1343 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001344 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001345 if (param->getAsConstantUnion() == nullptr)
1346 {
1347 return nullptr;
1348 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001349 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001350 TConstantUnion *constArray = nullptr;
1351 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001352 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001353 else
Olli Etuahof119a262016-08-19 15:54:22 +03001354 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001355
1356 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001357 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001358}
1359
Jamie Madillb1a85f42014-08-19 15:23:24 -04001360//
1361// The fold functions see if an operation on a constant can be done in place,
1362// without generating run-time code.
1363//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001364// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001365//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001366TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1367 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001368 TDiagnostics *diagnostics,
1369 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001370{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001371 const TConstantUnion *leftArray = getUnionArrayPointer();
1372 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001373
Olli Etuahof119a262016-08-19 15:54:22 +03001374 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001375
1376 size_t objectSize = getType().getObjectSize();
1377
1378 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1379 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1380 {
1381 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1382 }
1383 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1384 {
1385 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001386 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001387 objectSize = rightNode->getType().getObjectSize();
1388 }
1389
1390 TConstantUnion *resultArray = nullptr;
1391
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001392 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001393 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001394 case EOpAdd:
1395 resultArray = new TConstantUnion[objectSize];
1396 for (size_t i = 0; i < objectSize; i++)
1397 resultArray[i] =
1398 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1399 break;
1400 case EOpSub:
1401 resultArray = new TConstantUnion[objectSize];
1402 for (size_t i = 0; i < objectSize; i++)
1403 resultArray[i] =
1404 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1405 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001406
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001407 case EOpMul:
1408 case EOpVectorTimesScalar:
1409 case EOpMatrixTimesScalar:
1410 resultArray = new TConstantUnion[objectSize];
1411 for (size_t i = 0; i < objectSize; i++)
1412 resultArray[i] =
1413 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1414 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001415
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001416 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001417 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001418 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001419 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001420
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001421 const int leftCols = getCols();
1422 const int leftRows = getRows();
1423 const int rightCols = rightNode->getType().getCols();
1424 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001425 const int resultCols = rightCols;
1426 const int resultRows = leftRows;
1427
1428 resultArray = new TConstantUnion[resultCols * resultRows];
1429 for (int row = 0; row < resultRows; row++)
1430 {
1431 for (int column = 0; column < resultCols; column++)
1432 {
1433 resultArray[resultRows * column + row].setFConst(0.0f);
1434 for (int i = 0; i < leftCols; i++)
1435 {
1436 resultArray[resultRows * column + row].setFConst(
1437 resultArray[resultRows * column + row].getFConst() +
1438 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001439 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001440 }
1441 }
1442 }
1443 }
1444 break;
1445
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001446 case EOpDiv:
1447 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001448 {
1449 resultArray = new TConstantUnion[objectSize];
1450 for (size_t i = 0; i < objectSize; i++)
1451 {
1452 switch (getType().getBasicType())
1453 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001454 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001455 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001456 ASSERT(op == EOpDiv);
1457 float dividend = leftArray[i].getFConst();
1458 float divisor = rightArray[i].getFConst();
1459 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001460 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001461 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001462 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001463 diagnostics->warning(
1464 getLine(),
1465 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001466 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001467 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001468 }
1469 else
1470 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001471 diagnostics->warning(getLine(),
1472 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001473 bool negativeResult =
1474 std::signbit(dividend) != std::signbit(divisor);
1475 resultArray[i].setFConst(
1476 negativeResult ? -std::numeric_limits<float>::infinity()
1477 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001478 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001479 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001480 else if (gl::isInf(dividend) && gl::isInf(divisor))
1481 {
1482 diagnostics->warning(getLine(),
1483 "Infinity divided by infinity during constant "
1484 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001485 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001486 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1487 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001488 else
1489 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001490 float result = dividend / divisor;
1491 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001492 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001493 diagnostics->warning(
1494 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001495 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001496 }
1497 resultArray[i].setFConst(result);
1498 }
1499 break;
1500 }
1501 case EbtInt:
1502 if (rightArray[i] == 0)
1503 {
1504 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001505 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001506 resultArray[i].setIConst(INT_MAX);
1507 }
1508 else
1509 {
1510 int lhs = leftArray[i].getIConst();
1511 int divisor = rightArray[i].getIConst();
1512 if (op == EOpDiv)
1513 {
1514 // Check for the special case where the minimum representable number
1515 // is
1516 // divided by -1. If left alone this leads to integer overflow in
1517 // C++.
1518 // ESSL 3.00.6 section 4.1.3 Integers:
1519 // "However, for the case where the minimum representable value is
1520 // divided by -1, it is allowed to return either the minimum
1521 // representable value or the maximum representable value."
1522 if (lhs == -0x7fffffff - 1 && divisor == -1)
1523 {
1524 resultArray[i].setIConst(0x7fffffff);
1525 }
1526 else
1527 {
1528 resultArray[i].setIConst(lhs / divisor);
1529 }
Olli Etuahod4453572016-09-27 13:21:46 +01001530 }
1531 else
1532 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001533 ASSERT(op == EOpIMod);
1534 if (lhs < 0 || divisor < 0)
1535 {
1536 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1537 // when
1538 // either one of the operands is negative.
1539 diagnostics->warning(getLine(),
1540 "Negative modulus operator operand "
1541 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001542 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001543 resultArray[i].setIConst(0);
1544 }
1545 else
1546 {
1547 resultArray[i].setIConst(lhs % divisor);
1548 }
Olli Etuahod4453572016-09-27 13:21:46 +01001549 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001550 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001551 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001552
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001553 case EbtUInt:
1554 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001555 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001556 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001557 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001558 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001559 }
1560 else
1561 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001562 if (op == EOpDiv)
1563 {
1564 resultArray[i].setUConst(leftArray[i].getUConst() /
1565 rightArray[i].getUConst());
1566 }
1567 else
1568 {
1569 ASSERT(op == EOpIMod);
1570 resultArray[i].setUConst(leftArray[i].getUConst() %
1571 rightArray[i].getUConst());
1572 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001573 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001574 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001575
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001576 default:
1577 UNREACHABLE();
1578 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001579 }
1580 }
1581 }
1582 break;
1583
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001584 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001585 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001586 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001587 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001588
1589 const int matrixCols = getCols();
1590 const int matrixRows = getRows();
1591
1592 resultArray = new TConstantUnion[matrixRows];
1593
1594 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1595 {
1596 resultArray[matrixRow].setFConst(0.0f);
1597 for (int col = 0; col < matrixCols; col++)
1598 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001599 resultArray[matrixRow].setFConst(
1600 resultArray[matrixRow].getFConst() +
1601 leftArray[col * matrixRows + matrixRow].getFConst() *
1602 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001603 }
1604 }
1605 }
1606 break;
1607
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001608 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001609 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001610 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001611 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001612
1613 const int matrixCols = rightNode->getType().getCols();
1614 const int matrixRows = rightNode->getType().getRows();
1615
1616 resultArray = new TConstantUnion[matrixCols];
1617
1618 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1619 {
1620 resultArray[matrixCol].setFConst(0.0f);
1621 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1622 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001623 resultArray[matrixCol].setFConst(
1624 resultArray[matrixCol].getFConst() +
1625 leftArray[matrixRow].getFConst() *
1626 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001627 }
1628 }
1629 }
1630 break;
1631
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001632 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001633 {
1634 resultArray = new TConstantUnion[objectSize];
1635 for (size_t i = 0; i < objectSize; i++)
1636 {
1637 resultArray[i] = leftArray[i] && rightArray[i];
1638 }
1639 }
1640 break;
1641
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001642 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001643 {
1644 resultArray = new TConstantUnion[objectSize];
1645 for (size_t i = 0; i < objectSize; i++)
1646 {
1647 resultArray[i] = leftArray[i] || rightArray[i];
1648 }
1649 }
1650 break;
1651
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001652 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001653 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001654 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001655 resultArray = new TConstantUnion[objectSize];
1656 for (size_t i = 0; i < objectSize; i++)
1657 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001658 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001659 }
1660 }
1661 break;
1662
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001663 case EOpBitwiseAnd:
1664 resultArray = new TConstantUnion[objectSize];
1665 for (size_t i = 0; i < objectSize; i++)
1666 resultArray[i] = leftArray[i] & rightArray[i];
1667 break;
1668 case EOpBitwiseXor:
1669 resultArray = new TConstantUnion[objectSize];
1670 for (size_t i = 0; i < objectSize; i++)
1671 resultArray[i] = leftArray[i] ^ rightArray[i];
1672 break;
1673 case EOpBitwiseOr:
1674 resultArray = new TConstantUnion[objectSize];
1675 for (size_t i = 0; i < objectSize; i++)
1676 resultArray[i] = leftArray[i] | rightArray[i];
1677 break;
1678 case EOpBitShiftLeft:
1679 resultArray = new TConstantUnion[objectSize];
1680 for (size_t i = 0; i < objectSize; i++)
1681 resultArray[i] =
1682 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1683 break;
1684 case EOpBitShiftRight:
1685 resultArray = new TConstantUnion[objectSize];
1686 for (size_t i = 0; i < objectSize; i++)
1687 resultArray[i] =
1688 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1689 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001690
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001691 case EOpLessThan:
1692 ASSERT(objectSize == 1);
1693 resultArray = new TConstantUnion[1];
1694 resultArray->setBConst(*leftArray < *rightArray);
1695 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001696
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001697 case EOpGreaterThan:
1698 ASSERT(objectSize == 1);
1699 resultArray = new TConstantUnion[1];
1700 resultArray->setBConst(*leftArray > *rightArray);
1701 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001702
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001703 case EOpLessThanEqual:
1704 ASSERT(objectSize == 1);
1705 resultArray = new TConstantUnion[1];
1706 resultArray->setBConst(!(*leftArray > *rightArray));
1707 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001708
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001709 case EOpGreaterThanEqual:
1710 ASSERT(objectSize == 1);
1711 resultArray = new TConstantUnion[1];
1712 resultArray->setBConst(!(*leftArray < *rightArray));
1713 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001714
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001715 case EOpEqual:
1716 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001717 {
1718 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001719 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001720 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001721 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001722 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001723 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001724 equal = false;
1725 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001726 }
1727 }
1728 if (op == EOpEqual)
1729 {
1730 resultArray->setBConst(equal);
1731 }
1732 else
1733 {
1734 resultArray->setBConst(!equal);
1735 }
1736 }
1737 break;
1738
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001739 default:
1740 UNREACHABLE();
1741 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001742 }
1743 return resultArray;
1744}
1745
Olli Etuahof119a262016-08-19 15:54:22 +03001746// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1747// code. Returns the constant value to keep using. Nullptr should not be returned.
1748TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001749{
Olli Etuahof119a262016-08-19 15:54:22 +03001750 // Do operations where the return type may have a different number of components compared to the
1751 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001752
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001753 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001754 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301755
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001756 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301757 TConstantUnion *resultArray = nullptr;
1758 switch (op)
1759 {
Olli Etuahof119a262016-08-19 15:54:22 +03001760 case EOpAny:
1761 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301762 resultArray = new TConstantUnion();
1763 resultArray->setBConst(false);
1764 for (size_t i = 0; i < objectSize; i++)
1765 {
1766 if (operandArray[i].getBConst())
1767 {
1768 resultArray->setBConst(true);
1769 break;
1770 }
1771 }
1772 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301773
Olli Etuahof119a262016-08-19 15:54:22 +03001774 case EOpAll:
1775 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301776 resultArray = new TConstantUnion();
1777 resultArray->setBConst(true);
1778 for (size_t i = 0; i < objectSize; i++)
1779 {
1780 if (!operandArray[i].getBConst())
1781 {
1782 resultArray->setBConst(false);
1783 break;
1784 }
1785 }
1786 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301787
Olli Etuahof119a262016-08-19 15:54:22 +03001788 case EOpLength:
1789 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301790 resultArray = new TConstantUnion();
1791 resultArray->setFConst(VectorLength(operandArray, objectSize));
1792 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301793
Olli Etuahof119a262016-08-19 15:54:22 +03001794 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301795 {
Olli Etuahof119a262016-08-19 15:54:22 +03001796 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301797 resultArray = new TConstantUnion[objectSize];
1798 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001799 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301800 SetUnionArrayFromMatrix(result, resultArray);
1801 break;
1802 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301803
Olli Etuahof119a262016-08-19 15:54:22 +03001804 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301805 {
Olli Etuahof119a262016-08-19 15:54:22 +03001806 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301807 unsigned int size = getType().getNominalSize();
1808 ASSERT(size >= 2 && size <= 4);
1809 resultArray = new TConstantUnion();
1810 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1811 break;
1812 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301813
Olli Etuahof119a262016-08-19 15:54:22 +03001814 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301815 {
Olli Etuahof119a262016-08-19 15:54:22 +03001816 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301817 unsigned int size = getType().getNominalSize();
1818 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001819 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301820 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1821 SetUnionArrayFromMatrix(result, resultArray);
1822 break;
1823 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301824
Olli Etuahof119a262016-08-19 15:54:22 +03001825 case EOpPackSnorm2x16:
1826 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301827 ASSERT(getType().getNominalSize() == 2);
1828 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001829 resultArray->setUConst(
1830 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301831 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301832
Olli Etuahof119a262016-08-19 15:54:22 +03001833 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301834 {
Olli Etuahof119a262016-08-19 15:54:22 +03001835 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301836 resultArray = new TConstantUnion[2];
1837 float f1, f2;
1838 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1839 resultArray[0].setFConst(f1);
1840 resultArray[1].setFConst(f2);
1841 break;
1842 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301843
Olli Etuahof119a262016-08-19 15:54:22 +03001844 case EOpPackUnorm2x16:
1845 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301846 ASSERT(getType().getNominalSize() == 2);
1847 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001848 resultArray->setUConst(
1849 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
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 EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301853 {
Olli Etuahof119a262016-08-19 15:54:22 +03001854 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301855 resultArray = new TConstantUnion[2];
1856 float f1, f2;
1857 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1858 resultArray[0].setFConst(f1);
1859 resultArray[1].setFConst(f2);
1860 break;
1861 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301862
Olli Etuahof119a262016-08-19 15:54:22 +03001863 case EOpPackHalf2x16:
1864 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301865 ASSERT(getType().getNominalSize() == 2);
1866 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001867 resultArray->setUConst(
1868 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301869 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301870
Olli Etuahof119a262016-08-19 15:54:22 +03001871 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301872 {
Olli Etuahof119a262016-08-19 15:54:22 +03001873 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301874 resultArray = new TConstantUnion[2];
1875 float f1, f2;
1876 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1877 resultArray[0].setFConst(f1);
1878 resultArray[1].setFConst(f2);
1879 break;
1880 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301881
Olli Etuaho25aef452017-01-29 16:15:44 -08001882 case EOpPackUnorm4x8:
1883 {
1884 ASSERT(getType().getBasicType() == EbtFloat);
1885 resultArray = new TConstantUnion();
1886 resultArray->setUConst(
1887 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1888 operandArray[2].getFConst(), operandArray[3].getFConst()));
1889 break;
1890 }
1891 case EOpPackSnorm4x8:
1892 {
1893 ASSERT(getType().getBasicType() == EbtFloat);
1894 resultArray = new TConstantUnion();
1895 resultArray->setUConst(
1896 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1897 operandArray[2].getFConst(), operandArray[3].getFConst()));
1898 break;
1899 }
1900 case EOpUnpackUnorm4x8:
1901 {
1902 ASSERT(getType().getBasicType() == EbtUInt);
1903 resultArray = new TConstantUnion[4];
1904 float f[4];
1905 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
1906 for (size_t i = 0; i < 4; ++i)
1907 {
1908 resultArray[i].setFConst(f[i]);
1909 }
1910 break;
1911 }
1912 case EOpUnpackSnorm4x8:
1913 {
1914 ASSERT(getType().getBasicType() == EbtUInt);
1915 resultArray = new TConstantUnion[4];
1916 float f[4];
1917 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
1918 for (size_t i = 0; i < 4; ++i)
1919 {
1920 resultArray[i].setFConst(f[i]);
1921 }
1922 break;
1923 }
1924
Olli Etuahof119a262016-08-19 15:54:22 +03001925 default:
1926 UNREACHABLE();
1927 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301928 }
1929
1930 return resultArray;
1931}
1932
Olli Etuahof119a262016-08-19 15:54:22 +03001933TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1934 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301935{
Olli Etuahof119a262016-08-19 15:54:22 +03001936 // Do unary operations where each component of the result is computed based on the corresponding
1937 // component of the operand. Also folds normalize, though the divisor in that case takes all
1938 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301939
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001940 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001941 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001942
1943 size_t objectSize = getType().getObjectSize();
1944
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1946 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301947 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001948 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301949 {
Olli Etuahof119a262016-08-19 15:54:22 +03001950 case EOpNegative:
1951 switch (getType().getBasicType())
1952 {
1953 case EbtFloat:
1954 resultArray[i].setFConst(-operandArray[i].getFConst());
1955 break;
1956 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001957 if (operandArray[i] == std::numeric_limits<int>::min())
1958 {
1959 // The minimum representable integer doesn't have a positive
1960 // counterpart, rather the negation overflows and in ESSL is supposed to
1961 // wrap back to the minimum representable integer. Make sure that we
1962 // don't actually let the negation overflow, which has undefined
1963 // behavior in C++.
1964 resultArray[i].setIConst(std::numeric_limits<int>::min());
1965 }
1966 else
1967 {
1968 resultArray[i].setIConst(-operandArray[i].getIConst());
1969 }
Olli Etuahof119a262016-08-19 15:54:22 +03001970 break;
1971 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001972 if (operandArray[i] == 0x80000000u)
1973 {
1974 resultArray[i].setUConst(0x80000000u);
1975 }
1976 else
1977 {
1978 resultArray[i].setUConst(static_cast<unsigned int>(
1979 -static_cast<int>(operandArray[i].getUConst())));
1980 }
Olli Etuahof119a262016-08-19 15:54:22 +03001981 break;
1982 default:
1983 UNREACHABLE();
1984 return nullptr;
1985 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301986 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301987
Olli Etuahof119a262016-08-19 15:54:22 +03001988 case EOpPositive:
1989 switch (getType().getBasicType())
1990 {
1991 case EbtFloat:
1992 resultArray[i].setFConst(operandArray[i].getFConst());
1993 break;
1994 case EbtInt:
1995 resultArray[i].setIConst(operandArray[i].getIConst());
1996 break;
1997 case EbtUInt:
1998 resultArray[i].setUConst(static_cast<unsigned int>(
1999 static_cast<int>(operandArray[i].getUConst())));
2000 break;
2001 default:
2002 UNREACHABLE();
2003 return nullptr;
2004 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302005 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302006
Olli Etuahof119a262016-08-19 15:54:22 +03002007 case EOpLogicalNot:
2008 switch (getType().getBasicType())
2009 {
2010 case EbtBool:
2011 resultArray[i].setBConst(!operandArray[i].getBConst());
2012 break;
2013 default:
2014 UNREACHABLE();
2015 return nullptr;
2016 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302017 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302018
Olli Etuahof119a262016-08-19 15:54:22 +03002019 case EOpBitwiseNot:
2020 switch (getType().getBasicType())
2021 {
2022 case EbtInt:
2023 resultArray[i].setIConst(~operandArray[i].getIConst());
2024 break;
2025 case EbtUInt:
2026 resultArray[i].setUConst(~operandArray[i].getUConst());
2027 break;
2028 default:
2029 UNREACHABLE();
2030 return nullptr;
2031 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302032 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302033
Olli Etuahof119a262016-08-19 15:54:22 +03002034 case EOpRadians:
2035 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302036 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2037 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302038
Olli Etuahof119a262016-08-19 15:54:22 +03002039 case EOpDegrees:
2040 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302041 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2042 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302043
Olli Etuahof119a262016-08-19 15:54:22 +03002044 case EOpSin:
2045 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302046 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302047
Olli Etuahof119a262016-08-19 15:54:22 +03002048 case EOpCos:
2049 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2050 break;
2051
2052 case EOpTan:
2053 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2054 break;
2055
2056 case EOpAsin:
2057 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2058 // 0.
2059 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2060 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2061 diagnostics, &resultArray[i]);
2062 else
2063 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2064 break;
2065
2066 case EOpAcos:
2067 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2068 // 0.
2069 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2070 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2071 diagnostics, &resultArray[i]);
2072 else
2073 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2074 break;
2075
2076 case EOpAtan:
2077 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2078 break;
2079
2080 case EOpSinh:
2081 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2082 break;
2083
2084 case EOpCosh:
2085 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2086 break;
2087
2088 case EOpTanh:
2089 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2090 break;
2091
2092 case EOpAsinh:
2093 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2094 break;
2095
2096 case EOpAcosh:
2097 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2098 if (operandArray[i].getFConst() < 1.0f)
2099 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2100 diagnostics, &resultArray[i]);
2101 else
2102 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2103 break;
2104
2105 case EOpAtanh:
2106 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2107 // 0.
2108 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2109 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2110 diagnostics, &resultArray[i]);
2111 else
2112 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2113 break;
2114
2115 case EOpAbs:
2116 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302117 {
Olli Etuahof119a262016-08-19 15:54:22 +03002118 case EbtFloat:
2119 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2120 break;
2121 case EbtInt:
2122 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2123 break;
2124 default:
2125 UNREACHABLE();
2126 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302127 }
2128 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002129
2130 case EOpSign:
2131 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302132 {
Olli Etuahof119a262016-08-19 15:54:22 +03002133 case EbtFloat:
2134 {
2135 float fConst = operandArray[i].getFConst();
2136 float fResult = 0.0f;
2137 if (fConst > 0.0f)
2138 fResult = 1.0f;
2139 else if (fConst < 0.0f)
2140 fResult = -1.0f;
2141 resultArray[i].setFConst(fResult);
2142 break;
2143 }
2144 case EbtInt:
2145 {
2146 int iConst = operandArray[i].getIConst();
2147 int iResult = 0;
2148 if (iConst > 0)
2149 iResult = 1;
2150 else if (iConst < 0)
2151 iResult = -1;
2152 resultArray[i].setIConst(iResult);
2153 break;
2154 }
2155 default:
2156 UNREACHABLE();
2157 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302158 }
2159 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302160
Olli Etuahof119a262016-08-19 15:54:22 +03002161 case EOpFloor:
2162 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2163 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302164
Olli Etuahof119a262016-08-19 15:54:22 +03002165 case EOpTrunc:
2166 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2167 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302168
Olli Etuahof119a262016-08-19 15:54:22 +03002169 case EOpRound:
2170 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2171 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302172
Olli Etuahof119a262016-08-19 15:54:22 +03002173 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302174 {
Olli Etuahof119a262016-08-19 15:54:22 +03002175 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302176 float x = operandArray[i].getFConst();
2177 float result;
2178 float fractPart = modff(x, &result);
2179 if (fabsf(fractPart) == 0.5f)
2180 result = 2.0f * roundf(x / 2.0f);
2181 else
2182 result = roundf(x);
2183 resultArray[i].setFConst(result);
2184 break;
2185 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302186
Olli Etuahof119a262016-08-19 15:54:22 +03002187 case EOpCeil:
2188 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2189 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302190
Olli Etuahof119a262016-08-19 15:54:22 +03002191 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302192 {
Olli Etuahof119a262016-08-19 15:54:22 +03002193 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302194 float x = operandArray[i].getFConst();
2195 resultArray[i].setFConst(x - floorf(x));
2196 break;
2197 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302198
Olli Etuahof119a262016-08-19 15:54:22 +03002199 case EOpIsNan:
2200 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302201 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2202 break;
Arun Patole551279e2015-07-07 18:18:23 +05302203
Olli Etuahof119a262016-08-19 15:54:22 +03002204 case EOpIsInf:
2205 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302206 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2207 break;
Arun Patole551279e2015-07-07 18:18:23 +05302208
Olli Etuahof119a262016-08-19 15:54:22 +03002209 case EOpFloatBitsToInt:
2210 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302211 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2212 break;
Arun Patole551279e2015-07-07 18:18:23 +05302213
Olli Etuahof119a262016-08-19 15:54:22 +03002214 case EOpFloatBitsToUint:
2215 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302216 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2217 break;
Arun Patole551279e2015-07-07 18:18:23 +05302218
Olli Etuahof119a262016-08-19 15:54:22 +03002219 case EOpIntBitsToFloat:
2220 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302221 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2222 break;
Arun Patole551279e2015-07-07 18:18:23 +05302223
Olli Etuahof119a262016-08-19 15:54:22 +03002224 case EOpUintBitsToFloat:
2225 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302226 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2227 break;
Arun Patole551279e2015-07-07 18:18:23 +05302228
Olli Etuahof119a262016-08-19 15:54:22 +03002229 case EOpExp:
2230 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2231 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302232
Olli Etuahof119a262016-08-19 15:54:22 +03002233 case EOpLog:
2234 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2235 if (operandArray[i].getFConst() <= 0.0f)
2236 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2237 diagnostics, &resultArray[i]);
2238 else
2239 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2240 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302241
Olli Etuahof119a262016-08-19 15:54:22 +03002242 case EOpExp2:
2243 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2244 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302245
Olli Etuahof119a262016-08-19 15:54:22 +03002246 case EOpLog2:
2247 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2248 // And log2f is not available on some plarforms like old android, so just using
2249 // log(x)/log(2) here.
2250 if (operandArray[i].getFConst() <= 0.0f)
2251 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2252 diagnostics, &resultArray[i]);
2253 else
2254 {
2255 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2256 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2257 }
2258 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302259
Olli Etuahof119a262016-08-19 15:54:22 +03002260 case EOpSqrt:
2261 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2262 if (operandArray[i].getFConst() < 0.0f)
2263 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2264 diagnostics, &resultArray[i]);
2265 else
2266 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2267 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302268
Olli Etuahof119a262016-08-19 15:54:22 +03002269 case EOpInverseSqrt:
2270 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2271 // so getting the square root first using builtin function sqrt() and then taking
2272 // its inverse.
2273 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2274 // result to 0.
2275 if (operandArray[i].getFConst() <= 0.0f)
2276 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2277 diagnostics, &resultArray[i]);
2278 else
2279 {
2280 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2281 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2282 }
2283 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302284
Olli Etuahod68924e2017-01-02 17:34:40 +00002285 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002286 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302287 resultArray[i].setBConst(!operandArray[i].getBConst());
2288 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302289
Olli Etuahof119a262016-08-19 15:54:22 +03002290 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302291 {
Olli Etuahof119a262016-08-19 15:54:22 +03002292 ASSERT(getType().getBasicType() == EbtFloat);
2293 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302294 float length = VectorLength(operandArray, objectSize);
2295 if (length)
2296 resultArray[i].setFConst(x / length);
2297 else
Olli Etuahof119a262016-08-19 15:54:22 +03002298 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2299 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302300 break;
2301 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002302 case EOpBitfieldReverse:
2303 {
2304 uint32_t value;
2305 if (getType().getBasicType() == EbtInt)
2306 {
2307 value = static_cast<uint32_t>(operandArray[i].getIConst());
2308 }
2309 else
2310 {
2311 ASSERT(getType().getBasicType() == EbtUInt);
2312 value = operandArray[i].getUConst();
2313 }
2314 uint32_t result = gl::BitfieldReverse(value);
2315 if (getType().getBasicType() == EbtInt)
2316 {
2317 resultArray[i].setIConst(static_cast<int32_t>(result));
2318 }
2319 else
2320 {
2321 resultArray[i].setUConst(result);
2322 }
2323 break;
2324 }
2325 case EOpBitCount:
2326 {
2327 uint32_t value;
2328 if (getType().getBasicType() == EbtInt)
2329 {
2330 value = static_cast<uint32_t>(operandArray[i].getIConst());
2331 }
2332 else
2333 {
2334 ASSERT(getType().getBasicType() == EbtUInt);
2335 value = operandArray[i].getUConst();
2336 }
2337 int result = gl::BitCount(value);
2338 resultArray[i].setIConst(result);
2339 break;
2340 }
2341 case EOpFindLSB:
2342 {
2343 uint32_t value;
2344 if (getType().getBasicType() == EbtInt)
2345 {
2346 value = static_cast<uint32_t>(operandArray[i].getIConst());
2347 }
2348 else
2349 {
2350 ASSERT(getType().getBasicType() == EbtUInt);
2351 value = operandArray[i].getUConst();
2352 }
2353 resultArray[i].setIConst(gl::FindLSB(value));
2354 break;
2355 }
2356 case EOpFindMSB:
2357 {
2358 uint32_t value;
2359 if (getType().getBasicType() == EbtInt)
2360 {
2361 int intValue = operandArray[i].getIConst();
2362 value = static_cast<uint32_t>(intValue);
2363 if (intValue < 0)
2364 {
2365 // Look for zero instead of one in value. This also handles the intValue ==
2366 // -1 special case, where the return value needs to be -1.
2367 value = ~value;
2368 }
2369 }
2370 else
2371 {
2372 ASSERT(getType().getBasicType() == EbtUInt);
2373 value = operandArray[i].getUConst();
2374 }
2375 resultArray[i].setIConst(gl::FindMSB(value));
2376 break;
2377 }
Olli Etuahof119a262016-08-19 15:54:22 +03002378 case EOpDFdx:
2379 case EOpDFdy:
2380 case EOpFwidth:
2381 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302382 // Derivatives of constant arguments should be 0.
2383 resultArray[i].setFConst(0.0f);
2384 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302385
Olli Etuahof119a262016-08-19 15:54:22 +03002386 default:
2387 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302388 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302389 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002390
Arun Patoleab2b9a22015-07-06 18:27:56 +05302391 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002392}
2393
Olli Etuahof119a262016-08-19 15:54:22 +03002394void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2395 FloatTypeUnaryFunc builtinFunc,
2396 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302397{
2398 ASSERT(builtinFunc);
2399
Olli Etuahof119a262016-08-19 15:54:22 +03002400 ASSERT(getType().getBasicType() == EbtFloat);
2401 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302402}
2403
Jamie Madillb1a85f42014-08-19 15:23:24 -04002404// static
Olli Etuahof119a262016-08-19 15:54:22 +03002405TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002406{
2407 ASSERT(aggregate->getSequence()->size() > 0u);
2408 size_t resultSize = aggregate->getType().getObjectSize();
2409 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2410 TBasicType basicType = aggregate->getBasicType();
2411
2412 size_t resultIndex = 0u;
2413
2414 if (aggregate->getSequence()->size() == 1u)
2415 {
2416 TIntermNode *argument = aggregate->getSequence()->front();
2417 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2418 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2419 // Check the special case of constructing a matrix diagonal from a single scalar,
2420 // or a vector from a single scalar.
2421 if (argumentConstant->getType().getObjectSize() == 1u)
2422 {
2423 if (aggregate->isMatrix())
2424 {
2425 int resultCols = aggregate->getType().getCols();
2426 int resultRows = aggregate->getType().getRows();
2427 for (int col = 0; col < resultCols; ++col)
2428 {
2429 for (int row = 0; row < resultRows; ++row)
2430 {
2431 if (col == row)
2432 {
2433 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2434 }
2435 else
2436 {
2437 resultArray[resultIndex].setFConst(0.0f);
2438 }
2439 ++resultIndex;
2440 }
2441 }
2442 }
2443 else
2444 {
2445 while (resultIndex < resultSize)
2446 {
2447 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2448 ++resultIndex;
2449 }
2450 }
2451 ASSERT(resultIndex == resultSize);
2452 return resultArray;
2453 }
2454 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2455 {
2456 // The special case of constructing a matrix from a matrix.
2457 int argumentCols = argumentConstant->getType().getCols();
2458 int argumentRows = argumentConstant->getType().getRows();
2459 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002460 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002461 for (int col = 0; col < resultCols; ++col)
2462 {
2463 for (int row = 0; row < resultRows; ++row)
2464 {
2465 if (col < argumentCols && row < argumentRows)
2466 {
2467 resultArray[resultIndex].cast(basicType,
2468 argumentUnionArray[col * argumentRows + row]);
2469 }
2470 else if (col == row)
2471 {
2472 resultArray[resultIndex].setFConst(1.0f);
2473 }
2474 else
2475 {
2476 resultArray[resultIndex].setFConst(0.0f);
2477 }
2478 ++resultIndex;
2479 }
2480 }
2481 ASSERT(resultIndex == resultSize);
2482 return resultArray;
2483 }
2484 }
2485
2486 for (TIntermNode *&argument : *aggregate->getSequence())
2487 {
2488 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2489 size_t argumentSize = argumentConstant->getType().getObjectSize();
2490 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2491 for (size_t i = 0u; i < argumentSize; ++i)
2492 {
2493 if (resultIndex >= resultSize)
2494 break;
2495 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2496 ++resultIndex;
2497 }
2498 }
2499 ASSERT(resultIndex == resultSize);
2500 return resultArray;
2501}
2502
2503// static
Olli Etuahof119a262016-08-19 15:54:22 +03002504TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2505 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302506{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002507 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002508 TIntermSequence *arguments = aggregate->getSequence();
2509 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2510 std::vector<const TConstantUnion *> unionArrays(argsCount);
2511 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002512 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302513 TBasicType basicType = EbtVoid;
2514 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002515 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302516 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002517 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2518 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302519
2520 if (i == 0)
2521 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002522 basicType = argConstant->getType().getBasicType();
2523 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302524 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002525 unionArrays[i] = argConstant->getUnionArrayPointer();
2526 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002527 if (objectSizes[i] > maxObjectSize)
2528 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302529 }
2530
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002531 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302532 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002533 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302534 if (objectSizes[i] != maxObjectSize)
2535 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2536 }
Arun Patole274f0702015-05-05 13:33:30 +05302537
Olli Etuahob43846e2015-06-02 18:18:57 +03002538 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002539
2540 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302541 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002542 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302543 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002544 ASSERT(basicType == EbtFloat);
2545 resultArray = new TConstantUnion[maxObjectSize];
2546 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302547 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002548 float y = unionArrays[0][i].getFConst();
2549 float x = unionArrays[1][i].getFConst();
2550 // Results are undefined if x and y are both 0.
2551 if (x == 0.0f && y == 0.0f)
2552 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2553 else
2554 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302555 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002556 break;
2557 }
Arun Patolebf790422015-05-18 17:53:04 +05302558
Olli Etuaho51182ab2017-01-22 00:12:29 +00002559 case EOpPow:
2560 {
2561 ASSERT(basicType == EbtFloat);
2562 resultArray = new TConstantUnion[maxObjectSize];
2563 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302564 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002565 float x = unionArrays[0][i].getFConst();
2566 float y = unionArrays[1][i].getFConst();
2567 // Results are undefined if x < 0.
2568 // Results are undefined if x = 0 and y <= 0.
2569 if (x < 0.0f)
2570 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2571 else if (x == 0.0f && y <= 0.0f)
2572 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2573 else
2574 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302575 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002576 break;
2577 }
Arun Patolebf790422015-05-18 17:53:04 +05302578
Olli Etuaho51182ab2017-01-22 00:12:29 +00002579 case EOpMod:
2580 {
2581 ASSERT(basicType == EbtFloat);
2582 resultArray = new TConstantUnion[maxObjectSize];
2583 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302584 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002585 float x = unionArrays[0][i].getFConst();
2586 float y = unionArrays[1][i].getFConst();
2587 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302588 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002589 break;
2590 }
Arun Patolebf790422015-05-18 17:53:04 +05302591
Olli Etuaho51182ab2017-01-22 00:12:29 +00002592 case EOpMin:
2593 {
2594 resultArray = new TConstantUnion[maxObjectSize];
2595 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302596 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002597 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302598 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002599 case EbtFloat:
2600 resultArray[i].setFConst(
2601 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2602 break;
2603 case EbtInt:
2604 resultArray[i].setIConst(
2605 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2606 break;
2607 case EbtUInt:
2608 resultArray[i].setUConst(
2609 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2610 break;
2611 default:
2612 UNREACHABLE();
2613 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302614 }
2615 }
2616 break;
Arun Patole274f0702015-05-05 13:33:30 +05302617 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002618
2619 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302620 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002621 resultArray = new TConstantUnion[maxObjectSize];
2622 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302623 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002624 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302625 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002626 case EbtFloat:
2627 resultArray[i].setFConst(
2628 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2629 break;
2630 case EbtInt:
2631 resultArray[i].setIConst(
2632 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2633 break;
2634 case EbtUInt:
2635 resultArray[i].setUConst(
2636 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2637 break;
2638 default:
2639 UNREACHABLE();
2640 break;
Arun Patole274f0702015-05-05 13:33:30 +05302641 }
2642 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002643 break;
Arun Patole274f0702015-05-05 13:33:30 +05302644 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002645
2646 case EOpStep:
2647 {
2648 ASSERT(basicType == EbtFloat);
2649 resultArray = new TConstantUnion[maxObjectSize];
2650 for (size_t i = 0; i < maxObjectSize; i++)
2651 resultArray[i].setFConst(
2652 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2653 break;
2654 }
2655
2656 case EOpLessThanComponentWise:
2657 {
2658 resultArray = new TConstantUnion[maxObjectSize];
2659 for (size_t i = 0; i < maxObjectSize; i++)
2660 {
2661 switch (basicType)
2662 {
2663 case EbtFloat:
2664 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2665 unionArrays[1][i].getFConst());
2666 break;
2667 case EbtInt:
2668 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2669 unionArrays[1][i].getIConst());
2670 break;
2671 case EbtUInt:
2672 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2673 unionArrays[1][i].getUConst());
2674 break;
2675 default:
2676 UNREACHABLE();
2677 break;
2678 }
2679 }
2680 break;
2681 }
2682
2683 case EOpLessThanEqualComponentWise:
2684 {
2685 resultArray = new TConstantUnion[maxObjectSize];
2686 for (size_t i = 0; i < maxObjectSize; i++)
2687 {
2688 switch (basicType)
2689 {
2690 case EbtFloat:
2691 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2692 unionArrays[1][i].getFConst());
2693 break;
2694 case EbtInt:
2695 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2696 unionArrays[1][i].getIConst());
2697 break;
2698 case EbtUInt:
2699 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2700 unionArrays[1][i].getUConst());
2701 break;
2702 default:
2703 UNREACHABLE();
2704 break;
2705 }
2706 }
2707 break;
2708 }
2709
2710 case EOpGreaterThanComponentWise:
2711 {
2712 resultArray = new TConstantUnion[maxObjectSize];
2713 for (size_t i = 0; i < maxObjectSize; i++)
2714 {
2715 switch (basicType)
2716 {
2717 case EbtFloat:
2718 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2719 unionArrays[1][i].getFConst());
2720 break;
2721 case EbtInt:
2722 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2723 unionArrays[1][i].getIConst());
2724 break;
2725 case EbtUInt:
2726 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2727 unionArrays[1][i].getUConst());
2728 break;
2729 default:
2730 UNREACHABLE();
2731 break;
2732 }
2733 }
2734 break;
2735 }
2736 case EOpGreaterThanEqualComponentWise:
2737 {
2738 resultArray = new TConstantUnion[maxObjectSize];
2739 for (size_t i = 0; i < maxObjectSize; i++)
2740 {
2741 switch (basicType)
2742 {
2743 case EbtFloat:
2744 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2745 unionArrays[1][i].getFConst());
2746 break;
2747 case EbtInt:
2748 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2749 unionArrays[1][i].getIConst());
2750 break;
2751 case EbtUInt:
2752 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2753 unionArrays[1][i].getUConst());
2754 break;
2755 default:
2756 UNREACHABLE();
2757 break;
2758 }
2759 }
2760 }
2761 break;
2762
2763 case EOpEqualComponentWise:
2764 {
2765 resultArray = new TConstantUnion[maxObjectSize];
2766 for (size_t i = 0; i < maxObjectSize; i++)
2767 {
2768 switch (basicType)
2769 {
2770 case EbtFloat:
2771 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2772 unionArrays[1][i].getFConst());
2773 break;
2774 case EbtInt:
2775 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2776 unionArrays[1][i].getIConst());
2777 break;
2778 case EbtUInt:
2779 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2780 unionArrays[1][i].getUConst());
2781 break;
2782 case EbtBool:
2783 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2784 unionArrays[1][i].getBConst());
2785 break;
2786 default:
2787 UNREACHABLE();
2788 break;
2789 }
2790 }
2791 break;
2792 }
2793
2794 case EOpNotEqualComponentWise:
2795 {
2796 resultArray = new TConstantUnion[maxObjectSize];
2797 for (size_t i = 0; i < maxObjectSize; i++)
2798 {
2799 switch (basicType)
2800 {
2801 case EbtFloat:
2802 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2803 unionArrays[1][i].getFConst());
2804 break;
2805 case EbtInt:
2806 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2807 unionArrays[1][i].getIConst());
2808 break;
2809 case EbtUInt:
2810 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2811 unionArrays[1][i].getUConst());
2812 break;
2813 case EbtBool:
2814 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2815 unionArrays[1][i].getBConst());
2816 break;
2817 default:
2818 UNREACHABLE();
2819 break;
2820 }
2821 }
2822 break;
2823 }
2824
2825 case EOpDistance:
2826 {
2827 ASSERT(basicType == EbtFloat);
2828 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2829 resultArray = new TConstantUnion();
2830 for (size_t i = 0; i < maxObjectSize; i++)
2831 {
2832 float x = unionArrays[0][i].getFConst();
2833 float y = unionArrays[1][i].getFConst();
2834 distanceArray[i].setFConst(x - y);
2835 }
2836 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2837 break;
2838 }
2839
2840 case EOpDot:
2841 ASSERT(basicType == EbtFloat);
2842 resultArray = new TConstantUnion();
2843 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2844 break;
2845
2846 case EOpCross:
2847 {
2848 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2849 resultArray = new TConstantUnion[maxObjectSize];
2850 float x0 = unionArrays[0][0].getFConst();
2851 float x1 = unionArrays[0][1].getFConst();
2852 float x2 = unionArrays[0][2].getFConst();
2853 float y0 = unionArrays[1][0].getFConst();
2854 float y1 = unionArrays[1][1].getFConst();
2855 float y2 = unionArrays[1][2].getFConst();
2856 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2857 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2858 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2859 break;
2860 }
2861
2862 case EOpReflect:
2863 {
2864 ASSERT(basicType == EbtFloat);
2865 // genType reflect (genType I, genType N) :
2866 // For the incident vector I and surface orientation N, returns the reflection
2867 // direction:
2868 // I - 2 * dot(N, I) * N.
2869 resultArray = new TConstantUnion[maxObjectSize];
2870 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2871 for (size_t i = 0; i < maxObjectSize; i++)
2872 {
2873 float result = unionArrays[0][i].getFConst() -
2874 2.0f * dotProduct * unionArrays[1][i].getFConst();
2875 resultArray[i].setFConst(result);
2876 }
2877 break;
2878 }
2879
2880 case EOpMulMatrixComponentWise:
2881 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002882 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
2883 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00002884 // Perform component-wise matrix multiplication.
2885 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002886 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002887 angle::Matrix<float> result =
2888 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2889 SetUnionArrayFromMatrix(result, resultArray);
2890 break;
2891 }
2892
2893 case EOpOuterProduct:
2894 {
2895 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002896 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
2897 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002898 resultArray = new TConstantUnion[numRows * numCols];
2899 angle::Matrix<float> result =
2900 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2901 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
2902 SetUnionArrayFromMatrix(result, resultArray);
2903 break;
2904 }
2905
2906 case EOpClamp:
2907 {
2908 resultArray = new TConstantUnion[maxObjectSize];
2909 for (size_t i = 0; i < maxObjectSize; i++)
2910 {
2911 switch (basicType)
2912 {
2913 case EbtFloat:
2914 {
2915 float x = unionArrays[0][i].getFConst();
2916 float min = unionArrays[1][i].getFConst();
2917 float max = unionArrays[2][i].getFConst();
2918 // Results are undefined if min > max.
2919 if (min > max)
2920 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2921 &resultArray[i]);
2922 else
2923 resultArray[i].setFConst(gl::clamp(x, min, max));
2924 break;
2925 }
2926
2927 case EbtInt:
2928 {
2929 int x = unionArrays[0][i].getIConst();
2930 int min = unionArrays[1][i].getIConst();
2931 int max = unionArrays[2][i].getIConst();
2932 // Results are undefined if min > max.
2933 if (min > max)
2934 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2935 &resultArray[i]);
2936 else
2937 resultArray[i].setIConst(gl::clamp(x, min, max));
2938 break;
2939 }
2940 case EbtUInt:
2941 {
2942 unsigned int x = unionArrays[0][i].getUConst();
2943 unsigned int min = unionArrays[1][i].getUConst();
2944 unsigned int max = unionArrays[2][i].getUConst();
2945 // Results are undefined if min > max.
2946 if (min > max)
2947 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2948 &resultArray[i]);
2949 else
2950 resultArray[i].setUConst(gl::clamp(x, min, max));
2951 break;
2952 }
2953 default:
2954 UNREACHABLE();
2955 break;
2956 }
2957 }
2958 break;
2959 }
2960
2961 case EOpMix:
2962 {
2963 ASSERT(basicType == EbtFloat);
2964 resultArray = new TConstantUnion[maxObjectSize];
2965 for (size_t i = 0; i < maxObjectSize; i++)
2966 {
2967 float x = unionArrays[0][i].getFConst();
2968 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002969 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002970 if (type == EbtFloat)
2971 {
2972 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2973 float a = unionArrays[2][i].getFConst();
2974 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2975 }
2976 else // 3rd parameter is EbtBool
2977 {
2978 ASSERT(type == EbtBool);
2979 // Selects which vector each returned component comes from.
2980 // For a component of a that is false, the corresponding component of x is
2981 // returned.
2982 // For a component of a that is true, the corresponding component of y is
2983 // returned.
2984 bool a = unionArrays[2][i].getBConst();
2985 resultArray[i].setFConst(a ? y : x);
2986 }
2987 }
2988 break;
2989 }
2990
2991 case EOpSmoothStep:
2992 {
2993 ASSERT(basicType == EbtFloat);
2994 resultArray = new TConstantUnion[maxObjectSize];
2995 for (size_t i = 0; i < maxObjectSize; i++)
2996 {
2997 float edge0 = unionArrays[0][i].getFConst();
2998 float edge1 = unionArrays[1][i].getFConst();
2999 float x = unionArrays[2][i].getFConst();
3000 // Results are undefined if edge0 >= edge1.
3001 if (edge0 >= edge1)
3002 {
3003 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3004 }
3005 else
3006 {
3007 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3008 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3009 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3010 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3011 }
3012 }
3013 break;
3014 }
3015
Olli Etuaho74da73f2017-02-01 15:37:48 +00003016 case EOpLdexp:
3017 {
3018 resultArray = new TConstantUnion[maxObjectSize];
3019 for (size_t i = 0; i < maxObjectSize; i++)
3020 {
3021 float x = unionArrays[0][i].getFConst();
3022 int exp = unionArrays[1][i].getIConst();
3023 if (exp > 128)
3024 {
3025 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3026 }
3027 else
3028 {
3029 resultArray[i].setFConst(gl::Ldexp(x, exp));
3030 }
3031 }
3032 break;
3033 }
3034
Olli Etuaho51182ab2017-01-22 00:12:29 +00003035 case EOpFaceForward:
3036 {
3037 ASSERT(basicType == EbtFloat);
3038 // genType faceforward(genType N, genType I, genType Nref) :
3039 // If dot(Nref, I) < 0 return N, otherwise return -N.
3040 resultArray = new TConstantUnion[maxObjectSize];
3041 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3042 for (size_t i = 0; i < maxObjectSize; i++)
3043 {
3044 if (dotProduct < 0)
3045 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3046 else
3047 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3048 }
3049 break;
3050 }
3051
3052 case EOpRefract:
3053 {
3054 ASSERT(basicType == EbtFloat);
3055 // genType refract(genType I, genType N, float eta) :
3056 // For the incident vector I and surface normal N, and the ratio of indices of
3057 // refraction eta,
3058 // return the refraction vector. The result is computed by
3059 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3060 // if (k < 0.0)
3061 // return genType(0.0)
3062 // else
3063 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3064 resultArray = new TConstantUnion[maxObjectSize];
3065 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3066 for (size_t i = 0; i < maxObjectSize; i++)
3067 {
3068 float eta = unionArrays[2][i].getFConst();
3069 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3070 if (k < 0.0f)
3071 resultArray[i].setFConst(0.0f);
3072 else
3073 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3074 (eta * dotProduct + sqrtf(k)) *
3075 unionArrays[1][i].getFConst());
3076 }
3077 break;
3078 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003079 case EOpBitfieldExtract:
3080 {
3081 resultArray = new TConstantUnion[maxObjectSize];
3082 for (size_t i = 0; i < maxObjectSize; ++i)
3083 {
3084 int offset = unionArrays[1][0].getIConst();
3085 int bits = unionArrays[2][0].getIConst();
3086 if (bits == 0)
3087 {
3088 if (aggregate->getBasicType() == EbtInt)
3089 {
3090 resultArray[i].setIConst(0);
3091 }
3092 else
3093 {
3094 ASSERT(aggregate->getBasicType() == EbtUInt);
3095 resultArray[i].setUConst(0);
3096 }
3097 }
3098 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3099 {
3100 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3101 &resultArray[i]);
3102 }
3103 else
3104 {
3105 // bits can be 32 here, so we need to avoid bit shift overflow.
3106 uint32_t maskMsb = 1u << (bits - 1);
3107 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3108 if (aggregate->getBasicType() == EbtInt)
3109 {
3110 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3111 uint32_t resultUnsigned = (value & mask) >> offset;
3112 if ((resultUnsigned & maskMsb) != 0)
3113 {
3114 // The most significant bits (from bits+1 to the most significant bit)
3115 // should be set to 1.
3116 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3117 resultUnsigned |= higherBitsMask;
3118 }
3119 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3120 }
3121 else
3122 {
3123 ASSERT(aggregate->getBasicType() == EbtUInt);
3124 uint32_t value = unionArrays[0][i].getUConst();
3125 resultArray[i].setUConst((value & mask) >> offset);
3126 }
3127 }
3128 }
3129 break;
3130 }
3131 case EOpBitfieldInsert:
3132 {
3133 resultArray = new TConstantUnion[maxObjectSize];
3134 for (size_t i = 0; i < maxObjectSize; ++i)
3135 {
3136 int offset = unionArrays[2][0].getIConst();
3137 int bits = unionArrays[3][0].getIConst();
3138 if (bits == 0)
3139 {
3140 if (aggregate->getBasicType() == EbtInt)
3141 {
3142 int32_t base = unionArrays[0][i].getIConst();
3143 resultArray[i].setIConst(base);
3144 }
3145 else
3146 {
3147 ASSERT(aggregate->getBasicType() == EbtUInt);
3148 uint32_t base = unionArrays[0][i].getUConst();
3149 resultArray[i].setUConst(base);
3150 }
3151 }
3152 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3153 {
3154 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3155 &resultArray[i]);
3156 }
3157 else
3158 {
3159 // bits can be 32 here, so we need to avoid bit shift overflow.
3160 uint32_t maskMsb = 1u << (bits - 1);
3161 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3162 uint32_t baseMask = ~insertMask;
3163 if (aggregate->getBasicType() == EbtInt)
3164 {
3165 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3166 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3167 uint32_t resultUnsigned =
3168 (base & baseMask) | ((insert << offset) & insertMask);
3169 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3170 }
3171 else
3172 {
3173 ASSERT(aggregate->getBasicType() == EbtUInt);
3174 uint32_t base = unionArrays[0][i].getUConst();
3175 uint32_t insert = unionArrays[1][i].getUConst();
3176 resultArray[i].setUConst((base & baseMask) |
3177 ((insert << offset) & insertMask));
3178 }
3179 }
3180 }
3181 break;
3182 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003183
3184 default:
3185 UNREACHABLE();
3186 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303187 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003188 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303189}
3190
3191// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04003192TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
3193{
3194 if (hashFunction == NULL || name.empty())
3195 return name;
3196 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
3197 TStringStream stream;
3198 stream << HASHED_NAME_PREFIX << std::hex << number;
3199 TString hashedName = stream.str();
3200 return hashedName;
3201}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003202
3203void TIntermTraverser::updateTree()
3204{
Olli Etuahoa6f22092015-05-08 18:31:10 +03003205 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
3206 {
3207 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
3208 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003209 if (!insertion.insertionsAfter.empty())
3210 {
3211 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
3212 insertion.insertionsAfter);
3213 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003214 }
3215 if (!insertion.insertionsBefore.empty())
3216 {
3217 bool inserted =
3218 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
3219 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003220 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03003221 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003222 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
3223 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003224 const NodeUpdateEntry &replacement = mReplacements[ii];
3225 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003226 bool replaced =
3227 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003228 ASSERT(replaced);
3229
Olli Etuahocd94ef92015-04-16 19:18:10 +03003230 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003231 {
3232 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03003233 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003234 // be replaced, we need to make sure we don't update the replaced
3235 // node; instead, we update the replacement node.
3236 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
3237 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003238 NodeUpdateEntry &replacement2 = mReplacements[jj];
3239 if (replacement2.parent == replacement.original)
3240 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003241 }
3242 }
3243 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003244 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
3245 {
3246 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
3247 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003248 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
3249 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003250 ASSERT(replaced);
3251 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03003252
Jamie Madill03d863c2016-07-27 18:15:53 -04003253 clearReplacementQueue();
3254}
3255
3256void TIntermTraverser::clearReplacementQueue()
3257{
Olli Etuahod4f303e2015-05-20 17:09:06 +03003258 mReplacements.clear();
3259 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04003260 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003261}
Jamie Madill1048e432016-07-23 18:51:28 -04003262
Jamie Madill03d863c2016-07-27 18:15:53 -04003263void TIntermTraverser::queueReplacement(TIntermNode *original,
3264 TIntermNode *replacement,
3265 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003266{
Jamie Madill03d863c2016-07-27 18:15:53 -04003267 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04003268}
3269
Jamie Madill03d863c2016-07-27 18:15:53 -04003270void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
3271 TIntermNode *original,
3272 TIntermNode *replacement,
3273 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003274{
Jamie Madill03d863c2016-07-27 18:15:53 -04003275 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
3276 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04003277}
Jamie Madill45bcc782016-11-07 13:58:48 -05003278
3279} // namespace sh