blob: 276b6531464abde3d56579239b25b8ba7258a482 [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;
605}
606
Olli Etuahod7a25242015-08-18 13:49:45 +0300607TIntermBinary::TIntermBinary(const TIntermBinary &node)
608 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
609{
610 TIntermTyped *leftCopy = node.mLeft->deepCopy();
611 TIntermTyped *rightCopy = node.mRight->deepCopy();
612 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
613 mLeft = leftCopy;
614 mRight = rightCopy;
615}
616
617TIntermUnary::TIntermUnary(const TIntermUnary &node)
618 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
619{
620 TIntermTyped *operandCopy = node.mOperand->deepCopy();
621 ASSERT(operandCopy != nullptr);
622 mOperand = operandCopy;
623}
624
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300625TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300626{
Olli Etuahod7a25242015-08-18 13:49:45 +0300627 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300628 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
629 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300630 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300631 mCondition = conditionCopy;
632 mTrueExpression = trueCopy;
633 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300634}
635
Jamie Madillb1a85f42014-08-19 15:23:24 -0400636bool TIntermOperator::isAssignment() const
637{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300638 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400639}
640
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300641bool TIntermOperator::isMultiplication() const
642{
643 switch (mOp)
644 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500645 case EOpMul:
646 case EOpMatrixTimesMatrix:
647 case EOpMatrixTimesVector:
648 case EOpMatrixTimesScalar:
649 case EOpVectorTimesMatrix:
650 case EOpVectorTimesScalar:
651 return true;
652 default:
653 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300654 }
655}
656
Jamie Madillb1a85f42014-08-19 15:23:24 -0400657//
658// returns true if the operator is for one of the constructors
659//
660bool TIntermOperator::isConstructor() const
661{
662 switch (mOp)
663 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500664 case EOpConstructVec2:
665 case EOpConstructVec3:
666 case EOpConstructVec4:
667 case EOpConstructMat2:
668 case EOpConstructMat2x3:
669 case EOpConstructMat2x4:
670 case EOpConstructMat3x2:
671 case EOpConstructMat3:
672 case EOpConstructMat3x4:
673 case EOpConstructMat4x2:
674 case EOpConstructMat4x3:
675 case EOpConstructMat4:
676 case EOpConstructFloat:
677 case EOpConstructIVec2:
678 case EOpConstructIVec3:
679 case EOpConstructIVec4:
680 case EOpConstructInt:
681 case EOpConstructUVec2:
682 case EOpConstructUVec3:
683 case EOpConstructUVec4:
684 case EOpConstructUInt:
685 case EOpConstructBVec2:
686 case EOpConstructBVec3:
687 case EOpConstructBVec4:
688 case EOpConstructBool:
689 case EOpConstructStruct:
690 return true;
691 default:
692 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400693 }
694}
695
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800696bool TIntermOperator::isFunctionCall() const
697{
698 switch (mOp)
699 {
700 case EOpCallFunctionInAST:
701 case EOpCallBuiltInFunction:
702 case EOpCallInternalRawFunction:
703 return true;
704 default:
705 return false;
706 }
707}
708
Olli Etuaho1dded802016-08-18 18:13:13 +0300709TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
710{
711 if (left.isMatrix())
712 {
713 if (right.isMatrix())
714 {
715 return EOpMatrixTimesMatrix;
716 }
717 else
718 {
719 if (right.isVector())
720 {
721 return EOpMatrixTimesVector;
722 }
723 else
724 {
725 return EOpMatrixTimesScalar;
726 }
727 }
728 }
729 else
730 {
731 if (right.isMatrix())
732 {
733 if (left.isVector())
734 {
735 return EOpVectorTimesMatrix;
736 }
737 else
738 {
739 return EOpMatrixTimesScalar;
740 }
741 }
742 else
743 {
744 // Neither operand is a matrix.
745 if (left.isVector() == right.isVector())
746 {
747 // Leave as component product.
748 return EOpMul;
749 }
750 else
751 {
752 return EOpVectorTimesScalar;
753 }
754 }
755 }
756}
757
758TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
759{
760 if (left.isMatrix())
761 {
762 if (right.isMatrix())
763 {
764 return EOpMatrixTimesMatrixAssign;
765 }
766 else
767 {
768 // right should be scalar, but this may not be validated yet.
769 return EOpMatrixTimesScalarAssign;
770 }
771 }
772 else
773 {
774 if (right.isMatrix())
775 {
776 // Left should be a vector, but this may not be validated yet.
777 return EOpVectorTimesMatrixAssign;
778 }
779 else
780 {
781 // Neither operand is a matrix.
782 if (left.isVector() == right.isVector())
783 {
784 // Leave as component product.
785 return EOpMulAssign;
786 }
787 else
788 {
789 // left should be vector and right should be scalar, but this may not be validated
790 // yet.
791 return EOpVectorTimesScalarAssign;
792 }
793 }
794 }
795}
796
Jamie Madillb1a85f42014-08-19 15:23:24 -0400797//
798// Make sure the type of a unary operator is appropriate for its
799// combination of operation and operand type.
800//
Olli Etuahoa2234302016-08-31 12:05:39 +0300801void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400802{
Olli Etuahoa2234302016-08-31 12:05:39 +0300803 TQualifier resultQualifier = EvqTemporary;
804 if (mOperand->getQualifier() == EvqConst)
805 resultQualifier = EvqConst;
806
807 unsigned char operandPrimarySize =
808 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400809 switch (mOp)
810 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300811 case EOpFloatBitsToInt:
812 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
813 break;
814 case EOpFloatBitsToUint:
815 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
816 break;
817 case EOpIntBitsToFloat:
818 case EOpUintBitsToFloat:
819 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
820 break;
821 case EOpPackSnorm2x16:
822 case EOpPackUnorm2x16:
823 case EOpPackHalf2x16:
824 setType(TType(EbtUInt, EbpHigh, resultQualifier));
825 break;
826 case EOpUnpackSnorm2x16:
827 case EOpUnpackUnorm2x16:
828 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
829 break;
830 case EOpUnpackHalf2x16:
831 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
832 break;
833 case EOpAny:
834 case EOpAll:
835 setType(TType(EbtBool, EbpUndefined, resultQualifier));
836 break;
837 case EOpLength:
838 case EOpDeterminant:
839 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
840 break;
841 case EOpTranspose:
842 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
843 static_cast<unsigned char>(mOperand->getType().getRows()),
844 static_cast<unsigned char>(mOperand->getType().getCols())));
845 break;
846 case EOpIsInf:
847 case EOpIsNan:
848 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
849 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000850 case EOpBitfieldReverse:
851 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
852 break;
853 case EOpBitCount:
854 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
855 break;
856 case EOpFindLSB:
857 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
858 break;
859 case EOpFindMSB:
860 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
861 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300862 default:
863 setType(mOperand->getType());
864 mType.setQualifier(resultQualifier);
865 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400866 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300867}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400868
Olli Etuahob6fa0432016-09-28 16:28:05 +0100869TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
870 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
871 mOperand(operand),
872 mSwizzleOffsets(swizzleOffsets)
873{
874 ASSERT(mSwizzleOffsets.size() <= 4);
875 promote();
876}
877
Olli Etuahoa2234302016-08-31 12:05:39 +0300878TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
879 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
880{
881 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400882}
883
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300884TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
885 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
886{
887 promote();
888}
889
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000890TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
891 : TIntermNode(), mSymbol(symbol)
892{
893 ASSERT(symbol);
894 setLine(line);
895}
896
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300897TIntermTernary::TIntermTernary(TIntermTyped *cond,
898 TIntermTyped *trueExpression,
899 TIntermTyped *falseExpression)
900 : TIntermTyped(trueExpression->getType()),
901 mCondition(cond),
902 mTrueExpression(trueExpression),
903 mFalseExpression(falseExpression)
904{
905 getTypePointer()->setQualifier(
906 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
907}
908
909// static
910TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
911 TIntermTyped *trueExpression,
912 TIntermTyped *falseExpression)
913{
914 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
915 falseExpression->getQualifier() == EvqConst)
916 {
917 return EvqConst;
918 }
919 return EvqTemporary;
920}
921
Olli Etuahob6fa0432016-09-28 16:28:05 +0100922void TIntermSwizzle::promote()
923{
924 TQualifier resultQualifier = EvqTemporary;
925 if (mOperand->getQualifier() == EvqConst)
926 resultQualifier = EvqConst;
927
928 auto numFields = mSwizzleOffsets.size();
929 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
930 static_cast<unsigned char>(numFields)));
931}
932
933bool TIntermSwizzle::hasDuplicateOffsets() const
934{
935 int offsetCount[4] = {0u, 0u, 0u, 0u};
936 for (const auto offset : mSwizzleOffsets)
937 {
938 offsetCount[offset]++;
939 if (offsetCount[offset] > 1)
940 {
941 return true;
942 }
943 }
944 return false;
945}
946
Olli Etuaho09b04a22016-12-15 13:30:26 +0000947bool TIntermSwizzle::offsetsMatch(int offset) const
948{
949 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
950}
951
Olli Etuahob6fa0432016-09-28 16:28:05 +0100952void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
953{
954 for (const int offset : mSwizzleOffsets)
955 {
956 switch (offset)
957 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500958 case 0:
959 *out << "x";
960 break;
961 case 1:
962 *out << "y";
963 break;
964 case 2:
965 *out << "z";
966 break;
967 case 3:
968 *out << "w";
969 break;
970 default:
971 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +0100972 }
973 }
974}
975
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100976TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
977 const TIntermTyped *left,
978 const TIntermTyped *right)
979{
980 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
981 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
982 right->getQualifier() != EvqConst)
983 {
984 return EvqTemporary;
985 }
986 return EvqConst;
987}
Olli Etuahob6fa0432016-09-28 16:28:05 +0100988
989// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300990void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400991{
Olli Etuaho1dded802016-08-18 18:13:13 +0300992 ASSERT(!isMultiplication() ||
993 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
994
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100995 // Comma is handled as a special case.
996 if (mOp == EOpComma)
997 {
998 setType(mRight->getType());
999 return;
1000 }
1001
Jamie Madillb1a85f42014-08-19 15:23:24 -04001002 // Base assumption: just make the type the same as the left
1003 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001004 setType(mLeft->getType());
1005
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001006 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001007 // Binary operations results in temporary variables unless both
1008 // operands are const.
1009 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1010 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001011 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001012 getTypePointer()->setQualifier(EvqTemporary);
1013 }
1014
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001015 // Handle indexing ops.
1016 switch (mOp)
1017 {
1018 case EOpIndexDirect:
1019 case EOpIndexIndirect:
1020 if (mLeft->isArray())
1021 {
1022 mType.clearArrayness();
1023 }
1024 else if (mLeft->isMatrix())
1025 {
1026 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1027 static_cast<unsigned char>(mLeft->getRows())));
1028 }
1029 else if (mLeft->isVector())
1030 {
1031 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1032 }
1033 else
1034 {
1035 UNREACHABLE();
1036 }
1037 return;
1038 case EOpIndexDirectStruct:
1039 {
1040 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1041 const int i = mRight->getAsConstantUnion()->getIConst(0);
1042 setType(*fields[i]->type());
1043 getTypePointer()->setQualifier(resultQualifier);
1044 return;
1045 }
1046 case EOpIndexDirectInterfaceBlock:
1047 {
1048 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1049 const int i = mRight->getAsConstantUnion()->getIConst(0);
1050 setType(*fields[i]->type());
1051 getTypePointer()->setQualifier(resultQualifier);
1052 return;
1053 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001054 default:
1055 break;
1056 }
1057
1058 ASSERT(mLeft->isArray() == mRight->isArray());
1059
1060 // The result gets promoted to the highest precision.
1061 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1062 getTypePointer()->setPrecision(higherPrecision);
1063
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001064 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001065
1066 //
1067 // All scalars or structs. Code after this test assumes this case is removed!
1068 //
1069 if (nominalSize == 1)
1070 {
1071 switch (mOp)
1072 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001073 //
1074 // Promote to conditional
1075 //
1076 case EOpEqual:
1077 case EOpNotEqual:
1078 case EOpLessThan:
1079 case EOpGreaterThan:
1080 case EOpLessThanEqual:
1081 case EOpGreaterThanEqual:
1082 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1083 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001084
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001085 //
1086 // And and Or operate on conditionals
1087 //
1088 case EOpLogicalAnd:
1089 case EOpLogicalXor:
1090 case EOpLogicalOr:
1091 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1092 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1093 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001094
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001095 default:
1096 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001097 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001098 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001099 }
1100
1101 // If we reach here, at least one of the operands is vector or matrix.
1102 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001103 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001104
Jamie Madillb1a85f42014-08-19 15:23:24 -04001105 switch (mOp)
1106 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001107 case EOpMul:
1108 break;
1109 case EOpMatrixTimesScalar:
1110 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001111 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001112 setType(TType(basicType, higherPrecision, resultQualifier,
1113 static_cast<unsigned char>(mRight->getCols()),
1114 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001115 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001116 break;
1117 case EOpMatrixTimesVector:
1118 setType(TType(basicType, higherPrecision, resultQualifier,
1119 static_cast<unsigned char>(mLeft->getRows()), 1));
1120 break;
1121 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001122 setType(TType(basicType, higherPrecision, resultQualifier,
1123 static_cast<unsigned char>(mRight->getCols()),
1124 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001125 break;
1126 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001127 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001128 static_cast<unsigned char>(nominalSize), 1));
1129 break;
1130 case EOpVectorTimesMatrix:
1131 setType(TType(basicType, higherPrecision, resultQualifier,
1132 static_cast<unsigned char>(mRight->getCols()), 1));
1133 break;
1134 case EOpMulAssign:
1135 case EOpVectorTimesScalarAssign:
1136 case EOpVectorTimesMatrixAssign:
1137 case EOpMatrixTimesScalarAssign:
1138 case EOpMatrixTimesMatrixAssign:
1139 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1140 break;
1141 case EOpAssign:
1142 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001143 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1144 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1145 break;
1146 case EOpAdd:
1147 case EOpSub:
1148 case EOpDiv:
1149 case EOpIMod:
1150 case EOpBitShiftLeft:
1151 case EOpBitShiftRight:
1152 case EOpBitwiseAnd:
1153 case EOpBitwiseXor:
1154 case EOpBitwiseOr:
1155 case EOpAddAssign:
1156 case EOpSubAssign:
1157 case EOpDivAssign:
1158 case EOpIModAssign:
1159 case EOpBitShiftLeftAssign:
1160 case EOpBitShiftRightAssign:
1161 case EOpBitwiseAndAssign:
1162 case EOpBitwiseXorAssign:
1163 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001164 {
1165 const int secondarySize =
1166 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1167 setType(TType(basicType, higherPrecision, resultQualifier,
1168 static_cast<unsigned char>(nominalSize),
1169 static_cast<unsigned char>(secondarySize)));
1170 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001171 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001172 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001173 case EOpEqual:
1174 case EOpNotEqual:
1175 case EOpLessThan:
1176 case EOpGreaterThan:
1177 case EOpLessThanEqual:
1178 case EOpGreaterThanEqual:
1179 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1180 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001181 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001182 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001183
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001184 case EOpIndexDirect:
1185 case EOpIndexIndirect:
1186 case EOpIndexDirectInterfaceBlock:
1187 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001188 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001189 UNREACHABLE();
1190 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001191 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001192 UNREACHABLE();
1193 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001194 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001195}
1196
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001197const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001198{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001199 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001200 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001201 ASSERT(index < static_cast<int>(getType().getArraySize()));
1202 TType arrayElementType = getType();
1203 arrayElementType.clearArrayness();
1204 size_t arrayElementSize = arrayElementType.getObjectSize();
1205 return &mUnionArrayPointer[arrayElementSize * index];
1206 }
1207 else if (isMatrix())
1208 {
1209 ASSERT(index < getType().getCols());
1210 int size = getType().getRows();
1211 return &mUnionArrayPointer[size * index];
1212 }
1213 else if (isVector())
1214 {
1215 ASSERT(index < getType().getNominalSize());
1216 return &mUnionArrayPointer[index];
1217 }
1218 else
1219 {
1220 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001221 return nullptr;
1222 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001223}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001224
Olli Etuahob6fa0432016-09-28 16:28:05 +01001225TIntermTyped *TIntermSwizzle::fold()
1226{
1227 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1228 if (operandConstant == nullptr)
1229 {
1230 return nullptr;
1231 }
1232
1233 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1234 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1235 {
1236 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1237 }
1238 return CreateFoldedNode(constArray, this, mType.getQualifier());
1239}
1240
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001241TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1242{
1243 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1244 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1245 switch (mOp)
1246 {
1247 case EOpIndexDirect:
1248 {
1249 if (leftConstant == nullptr || rightConstant == nullptr)
1250 {
1251 return nullptr;
1252 }
1253 int index = rightConstant->getIConst(0);
1254
1255 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1256 return CreateFoldedNode(constArray, this, mType.getQualifier());
1257 }
1258 case EOpIndexDirectStruct:
1259 {
1260 if (leftConstant == nullptr || rightConstant == nullptr)
1261 {
1262 return nullptr;
1263 }
1264 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1265 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1266
1267 size_t previousFieldsSize = 0;
1268 for (size_t i = 0; i < index; ++i)
1269 {
1270 previousFieldsSize += fields[i]->type()->getObjectSize();
1271 }
1272
1273 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1274 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1275 }
1276 case EOpIndexIndirect:
1277 case EOpIndexDirectInterfaceBlock:
1278 // Can never be constant folded.
1279 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001280 default:
1281 {
1282 if (leftConstant == nullptr || rightConstant == nullptr)
1283 {
1284 return nullptr;
1285 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001286 TConstantUnion *constArray =
1287 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001288
1289 // Nodes may be constant folded without being qualified as constant.
1290 return CreateFoldedNode(constArray, this, mType.getQualifier());
1291 }
1292 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001293}
1294
Olli Etuahof119a262016-08-19 15:54:22 +03001295TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001296{
1297 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1298 if (operandConstant == nullptr)
1299 {
1300 return nullptr;
1301 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301302
1303 TConstantUnion *constArray = nullptr;
1304 switch (mOp)
1305 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001306 case EOpAny:
1307 case EOpAll:
1308 case EOpLength:
1309 case EOpTranspose:
1310 case EOpDeterminant:
1311 case EOpInverse:
1312 case EOpPackSnorm2x16:
1313 case EOpUnpackSnorm2x16:
1314 case EOpPackUnorm2x16:
1315 case EOpUnpackUnorm2x16:
1316 case EOpPackHalf2x16:
1317 case EOpUnpackHalf2x16:
1318 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1319 break;
1320 default:
1321 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1322 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301323 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001324
1325 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001326 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001327}
1328
Olli Etuahof119a262016-08-19 15:54:22 +03001329TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001330{
1331 // Make sure that all params are constant before actual constant folding.
1332 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001333 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001334 if (param->getAsConstantUnion() == nullptr)
1335 {
1336 return nullptr;
1337 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001338 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001339 TConstantUnion *constArray = nullptr;
1340 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001341 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001342 else
Olli Etuahof119a262016-08-19 15:54:22 +03001343 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001344
1345 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001346 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001347}
1348
Jamie Madillb1a85f42014-08-19 15:23:24 -04001349//
1350// The fold functions see if an operation on a constant can be done in place,
1351// without generating run-time code.
1352//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001353// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001354//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001355TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1356 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001357 TDiagnostics *diagnostics,
1358 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001359{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001360 const TConstantUnion *leftArray = getUnionArrayPointer();
1361 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001362
Olli Etuahof119a262016-08-19 15:54:22 +03001363 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001364
1365 size_t objectSize = getType().getObjectSize();
1366
1367 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1368 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1369 {
1370 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1371 }
1372 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1373 {
1374 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001375 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001376 objectSize = rightNode->getType().getObjectSize();
1377 }
1378
1379 TConstantUnion *resultArray = nullptr;
1380
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001381 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001382 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001383 case EOpAdd:
1384 resultArray = new TConstantUnion[objectSize];
1385 for (size_t i = 0; i < objectSize; i++)
1386 resultArray[i] =
1387 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1388 break;
1389 case EOpSub:
1390 resultArray = new TConstantUnion[objectSize];
1391 for (size_t i = 0; i < objectSize; i++)
1392 resultArray[i] =
1393 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1394 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001395
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001396 case EOpMul:
1397 case EOpVectorTimesScalar:
1398 case EOpMatrixTimesScalar:
1399 resultArray = new TConstantUnion[objectSize];
1400 for (size_t i = 0; i < objectSize; i++)
1401 resultArray[i] =
1402 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1403 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001404
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001405 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001406 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001407 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001408 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001409
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001410 const int leftCols = getCols();
1411 const int leftRows = getRows();
1412 const int rightCols = rightNode->getType().getCols();
1413 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001414 const int resultCols = rightCols;
1415 const int resultRows = leftRows;
1416
1417 resultArray = new TConstantUnion[resultCols * resultRows];
1418 for (int row = 0; row < resultRows; row++)
1419 {
1420 for (int column = 0; column < resultCols; column++)
1421 {
1422 resultArray[resultRows * column + row].setFConst(0.0f);
1423 for (int i = 0; i < leftCols; i++)
1424 {
1425 resultArray[resultRows * column + row].setFConst(
1426 resultArray[resultRows * column + row].getFConst() +
1427 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001428 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001429 }
1430 }
1431 }
1432 }
1433 break;
1434
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001435 case EOpDiv:
1436 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001437 {
1438 resultArray = new TConstantUnion[objectSize];
1439 for (size_t i = 0; i < objectSize; i++)
1440 {
1441 switch (getType().getBasicType())
1442 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001443 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001444 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001445 ASSERT(op == EOpDiv);
1446 float dividend = leftArray[i].getFConst();
1447 float divisor = rightArray[i].getFConst();
1448 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001449 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001450 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001451 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001452 diagnostics->warning(
1453 getLine(),
1454 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001455 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001456 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001457 }
1458 else
1459 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001460 diagnostics->warning(getLine(),
1461 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001462 bool negativeResult =
1463 std::signbit(dividend) != std::signbit(divisor);
1464 resultArray[i].setFConst(
1465 negativeResult ? -std::numeric_limits<float>::infinity()
1466 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001467 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001468 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001469 else if (gl::isInf(dividend) && gl::isInf(divisor))
1470 {
1471 diagnostics->warning(getLine(),
1472 "Infinity divided by infinity during constant "
1473 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001474 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001475 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1476 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001477 else
1478 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001479 float result = dividend / divisor;
1480 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001481 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001482 diagnostics->warning(
1483 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001484 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001485 }
1486 resultArray[i].setFConst(result);
1487 }
1488 break;
1489 }
1490 case EbtInt:
1491 if (rightArray[i] == 0)
1492 {
1493 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001494 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001495 resultArray[i].setIConst(INT_MAX);
1496 }
1497 else
1498 {
1499 int lhs = leftArray[i].getIConst();
1500 int divisor = rightArray[i].getIConst();
1501 if (op == EOpDiv)
1502 {
1503 // Check for the special case where the minimum representable number
1504 // is
1505 // divided by -1. If left alone this leads to integer overflow in
1506 // C++.
1507 // ESSL 3.00.6 section 4.1.3 Integers:
1508 // "However, for the case where the minimum representable value is
1509 // divided by -1, it is allowed to return either the minimum
1510 // representable value or the maximum representable value."
1511 if (lhs == -0x7fffffff - 1 && divisor == -1)
1512 {
1513 resultArray[i].setIConst(0x7fffffff);
1514 }
1515 else
1516 {
1517 resultArray[i].setIConst(lhs / divisor);
1518 }
Olli Etuahod4453572016-09-27 13:21:46 +01001519 }
1520 else
1521 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001522 ASSERT(op == EOpIMod);
1523 if (lhs < 0 || divisor < 0)
1524 {
1525 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1526 // when
1527 // either one of the operands is negative.
1528 diagnostics->warning(getLine(),
1529 "Negative modulus operator operand "
1530 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001531 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001532 resultArray[i].setIConst(0);
1533 }
1534 else
1535 {
1536 resultArray[i].setIConst(lhs % divisor);
1537 }
Olli Etuahod4453572016-09-27 13:21:46 +01001538 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001539 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001540 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001541
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001542 case EbtUInt:
1543 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001544 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001545 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001546 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001547 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001548 }
1549 else
1550 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001551 if (op == EOpDiv)
1552 {
1553 resultArray[i].setUConst(leftArray[i].getUConst() /
1554 rightArray[i].getUConst());
1555 }
1556 else
1557 {
1558 ASSERT(op == EOpIMod);
1559 resultArray[i].setUConst(leftArray[i].getUConst() %
1560 rightArray[i].getUConst());
1561 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001562 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001563 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001564
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001565 default:
1566 UNREACHABLE();
1567 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001568 }
1569 }
1570 }
1571 break;
1572
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001573 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001574 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001575 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001576 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001577
1578 const int matrixCols = getCols();
1579 const int matrixRows = getRows();
1580
1581 resultArray = new TConstantUnion[matrixRows];
1582
1583 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1584 {
1585 resultArray[matrixRow].setFConst(0.0f);
1586 for (int col = 0; col < matrixCols; col++)
1587 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001588 resultArray[matrixRow].setFConst(
1589 resultArray[matrixRow].getFConst() +
1590 leftArray[col * matrixRows + matrixRow].getFConst() *
1591 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001592 }
1593 }
1594 }
1595 break;
1596
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001597 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001598 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001599 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001600 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001601
1602 const int matrixCols = rightNode->getType().getCols();
1603 const int matrixRows = rightNode->getType().getRows();
1604
1605 resultArray = new TConstantUnion[matrixCols];
1606
1607 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1608 {
1609 resultArray[matrixCol].setFConst(0.0f);
1610 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1611 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001612 resultArray[matrixCol].setFConst(
1613 resultArray[matrixCol].getFConst() +
1614 leftArray[matrixRow].getFConst() *
1615 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001616 }
1617 }
1618 }
1619 break;
1620
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001621 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001622 {
1623 resultArray = new TConstantUnion[objectSize];
1624 for (size_t i = 0; i < objectSize; i++)
1625 {
1626 resultArray[i] = leftArray[i] && rightArray[i];
1627 }
1628 }
1629 break;
1630
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001631 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001632 {
1633 resultArray = new TConstantUnion[objectSize];
1634 for (size_t i = 0; i < objectSize; i++)
1635 {
1636 resultArray[i] = leftArray[i] || rightArray[i];
1637 }
1638 }
1639 break;
1640
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001641 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001642 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001643 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001644 resultArray = new TConstantUnion[objectSize];
1645 for (size_t i = 0; i < objectSize; i++)
1646 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001647 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001648 }
1649 }
1650 break;
1651
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001652 case EOpBitwiseAnd:
1653 resultArray = new TConstantUnion[objectSize];
1654 for (size_t i = 0; i < objectSize; i++)
1655 resultArray[i] = leftArray[i] & rightArray[i];
1656 break;
1657 case EOpBitwiseXor:
1658 resultArray = new TConstantUnion[objectSize];
1659 for (size_t i = 0; i < objectSize; i++)
1660 resultArray[i] = leftArray[i] ^ rightArray[i];
1661 break;
1662 case EOpBitwiseOr:
1663 resultArray = new TConstantUnion[objectSize];
1664 for (size_t i = 0; i < objectSize; i++)
1665 resultArray[i] = leftArray[i] | rightArray[i];
1666 break;
1667 case EOpBitShiftLeft:
1668 resultArray = new TConstantUnion[objectSize];
1669 for (size_t i = 0; i < objectSize; i++)
1670 resultArray[i] =
1671 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1672 break;
1673 case EOpBitShiftRight:
1674 resultArray = new TConstantUnion[objectSize];
1675 for (size_t i = 0; i < objectSize; i++)
1676 resultArray[i] =
1677 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1678 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001679
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001680 case EOpLessThan:
1681 ASSERT(objectSize == 1);
1682 resultArray = new TConstantUnion[1];
1683 resultArray->setBConst(*leftArray < *rightArray);
1684 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001685
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001686 case EOpGreaterThan:
1687 ASSERT(objectSize == 1);
1688 resultArray = new TConstantUnion[1];
1689 resultArray->setBConst(*leftArray > *rightArray);
1690 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001691
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001692 case EOpLessThanEqual:
1693 ASSERT(objectSize == 1);
1694 resultArray = new TConstantUnion[1];
1695 resultArray->setBConst(!(*leftArray > *rightArray));
1696 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001697
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001698 case EOpGreaterThanEqual:
1699 ASSERT(objectSize == 1);
1700 resultArray = new TConstantUnion[1];
1701 resultArray->setBConst(!(*leftArray < *rightArray));
1702 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001703
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001704 case EOpEqual:
1705 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001706 {
1707 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001708 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001709 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001710 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001711 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001712 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001713 equal = false;
1714 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001715 }
1716 }
1717 if (op == EOpEqual)
1718 {
1719 resultArray->setBConst(equal);
1720 }
1721 else
1722 {
1723 resultArray->setBConst(!equal);
1724 }
1725 }
1726 break;
1727
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001728 default:
1729 UNREACHABLE();
1730 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001731 }
1732 return resultArray;
1733}
1734
Olli Etuahof119a262016-08-19 15:54:22 +03001735// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1736// code. Returns the constant value to keep using. Nullptr should not be returned.
1737TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001738{
Olli Etuahof119a262016-08-19 15:54:22 +03001739 // Do operations where the return type may have a different number of components compared to the
1740 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001741
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001742 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001743 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301744
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001745 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301746 TConstantUnion *resultArray = nullptr;
1747 switch (op)
1748 {
Olli Etuahof119a262016-08-19 15:54:22 +03001749 case EOpAny:
1750 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301751 resultArray = new TConstantUnion();
1752 resultArray->setBConst(false);
1753 for (size_t i = 0; i < objectSize; i++)
1754 {
1755 if (operandArray[i].getBConst())
1756 {
1757 resultArray->setBConst(true);
1758 break;
1759 }
1760 }
1761 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301762
Olli Etuahof119a262016-08-19 15:54:22 +03001763 case EOpAll:
1764 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301765 resultArray = new TConstantUnion();
1766 resultArray->setBConst(true);
1767 for (size_t i = 0; i < objectSize; i++)
1768 {
1769 if (!operandArray[i].getBConst())
1770 {
1771 resultArray->setBConst(false);
1772 break;
1773 }
1774 }
1775 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301776
Olli Etuahof119a262016-08-19 15:54:22 +03001777 case EOpLength:
1778 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301779 resultArray = new TConstantUnion();
1780 resultArray->setFConst(VectorLength(operandArray, objectSize));
1781 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301782
Olli Etuahof119a262016-08-19 15:54:22 +03001783 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301784 {
Olli Etuahof119a262016-08-19 15:54:22 +03001785 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301786 resultArray = new TConstantUnion[objectSize];
1787 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001788 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301789 SetUnionArrayFromMatrix(result, resultArray);
1790 break;
1791 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301792
Olli Etuahof119a262016-08-19 15:54:22 +03001793 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301794 {
Olli Etuahof119a262016-08-19 15:54:22 +03001795 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301796 unsigned int size = getType().getNominalSize();
1797 ASSERT(size >= 2 && size <= 4);
1798 resultArray = new TConstantUnion();
1799 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1800 break;
1801 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301802
Olli Etuahof119a262016-08-19 15:54:22 +03001803 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301804 {
Olli Etuahof119a262016-08-19 15:54:22 +03001805 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301806 unsigned int size = getType().getNominalSize();
1807 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001808 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301809 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1810 SetUnionArrayFromMatrix(result, resultArray);
1811 break;
1812 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301813
Olli Etuahof119a262016-08-19 15:54:22 +03001814 case EOpPackSnorm2x16:
1815 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301816 ASSERT(getType().getNominalSize() == 2);
1817 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001818 resultArray->setUConst(
1819 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301820 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301821
Olli Etuahof119a262016-08-19 15:54:22 +03001822 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301823 {
Olli Etuahof119a262016-08-19 15:54:22 +03001824 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301825 resultArray = new TConstantUnion[2];
1826 float f1, f2;
1827 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1828 resultArray[0].setFConst(f1);
1829 resultArray[1].setFConst(f2);
1830 break;
1831 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301832
Olli Etuahof119a262016-08-19 15:54:22 +03001833 case EOpPackUnorm2x16:
1834 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301835 ASSERT(getType().getNominalSize() == 2);
1836 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001837 resultArray->setUConst(
1838 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301839 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301840
Olli Etuahof119a262016-08-19 15:54:22 +03001841 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301842 {
Olli Etuahof119a262016-08-19 15:54:22 +03001843 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301844 resultArray = new TConstantUnion[2];
1845 float f1, f2;
1846 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1847 resultArray[0].setFConst(f1);
1848 resultArray[1].setFConst(f2);
1849 break;
1850 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301851
Olli Etuahof119a262016-08-19 15:54:22 +03001852 case EOpPackHalf2x16:
1853 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301854 ASSERT(getType().getNominalSize() == 2);
1855 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001856 resultArray->setUConst(
1857 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301858 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301859
Olli Etuahof119a262016-08-19 15:54:22 +03001860 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301861 {
Olli Etuahof119a262016-08-19 15:54:22 +03001862 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301863 resultArray = new TConstantUnion[2];
1864 float f1, f2;
1865 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1866 resultArray[0].setFConst(f1);
1867 resultArray[1].setFConst(f2);
1868 break;
1869 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301870
Olli Etuahof119a262016-08-19 15:54:22 +03001871 default:
1872 UNREACHABLE();
1873 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301874 }
1875
1876 return resultArray;
1877}
1878
Olli Etuahof119a262016-08-19 15:54:22 +03001879TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1880 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301881{
Olli Etuahof119a262016-08-19 15:54:22 +03001882 // Do unary operations where each component of the result is computed based on the corresponding
1883 // component of the operand. Also folds normalize, though the divisor in that case takes all
1884 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301885
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001886 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001887 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001888
1889 size_t objectSize = getType().getObjectSize();
1890
Arun Patoleab2b9a22015-07-06 18:27:56 +05301891 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1892 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301893 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001894 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301895 {
Olli Etuahof119a262016-08-19 15:54:22 +03001896 case EOpNegative:
1897 switch (getType().getBasicType())
1898 {
1899 case EbtFloat:
1900 resultArray[i].setFConst(-operandArray[i].getFConst());
1901 break;
1902 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001903 if (operandArray[i] == std::numeric_limits<int>::min())
1904 {
1905 // The minimum representable integer doesn't have a positive
1906 // counterpart, rather the negation overflows and in ESSL is supposed to
1907 // wrap back to the minimum representable integer. Make sure that we
1908 // don't actually let the negation overflow, which has undefined
1909 // behavior in C++.
1910 resultArray[i].setIConst(std::numeric_limits<int>::min());
1911 }
1912 else
1913 {
1914 resultArray[i].setIConst(-operandArray[i].getIConst());
1915 }
Olli Etuahof119a262016-08-19 15:54:22 +03001916 break;
1917 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001918 if (operandArray[i] == 0x80000000u)
1919 {
1920 resultArray[i].setUConst(0x80000000u);
1921 }
1922 else
1923 {
1924 resultArray[i].setUConst(static_cast<unsigned int>(
1925 -static_cast<int>(operandArray[i].getUConst())));
1926 }
Olli Etuahof119a262016-08-19 15:54:22 +03001927 break;
1928 default:
1929 UNREACHABLE();
1930 return nullptr;
1931 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301932 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301933
Olli Etuahof119a262016-08-19 15:54:22 +03001934 case EOpPositive:
1935 switch (getType().getBasicType())
1936 {
1937 case EbtFloat:
1938 resultArray[i].setFConst(operandArray[i].getFConst());
1939 break;
1940 case EbtInt:
1941 resultArray[i].setIConst(operandArray[i].getIConst());
1942 break;
1943 case EbtUInt:
1944 resultArray[i].setUConst(static_cast<unsigned int>(
1945 static_cast<int>(operandArray[i].getUConst())));
1946 break;
1947 default:
1948 UNREACHABLE();
1949 return nullptr;
1950 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301951 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301952
Olli Etuahof119a262016-08-19 15:54:22 +03001953 case EOpLogicalNot:
1954 switch (getType().getBasicType())
1955 {
1956 case EbtBool:
1957 resultArray[i].setBConst(!operandArray[i].getBConst());
1958 break;
1959 default:
1960 UNREACHABLE();
1961 return nullptr;
1962 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301963 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301964
Olli Etuahof119a262016-08-19 15:54:22 +03001965 case EOpBitwiseNot:
1966 switch (getType().getBasicType())
1967 {
1968 case EbtInt:
1969 resultArray[i].setIConst(~operandArray[i].getIConst());
1970 break;
1971 case EbtUInt:
1972 resultArray[i].setUConst(~operandArray[i].getUConst());
1973 break;
1974 default:
1975 UNREACHABLE();
1976 return nullptr;
1977 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301978 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301979
Olli Etuahof119a262016-08-19 15:54:22 +03001980 case EOpRadians:
1981 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301982 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1983 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301984
Olli Etuahof119a262016-08-19 15:54:22 +03001985 case EOpDegrees:
1986 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301987 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1988 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301989
Olli Etuahof119a262016-08-19 15:54:22 +03001990 case EOpSin:
1991 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301992 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301993
Olli Etuahof119a262016-08-19 15:54:22 +03001994 case EOpCos:
1995 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1996 break;
1997
1998 case EOpTan:
1999 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2000 break;
2001
2002 case EOpAsin:
2003 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2004 // 0.
2005 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2006 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2007 diagnostics, &resultArray[i]);
2008 else
2009 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2010 break;
2011
2012 case EOpAcos:
2013 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2014 // 0.
2015 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2016 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2017 diagnostics, &resultArray[i]);
2018 else
2019 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2020 break;
2021
2022 case EOpAtan:
2023 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2024 break;
2025
2026 case EOpSinh:
2027 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2028 break;
2029
2030 case EOpCosh:
2031 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2032 break;
2033
2034 case EOpTanh:
2035 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2036 break;
2037
2038 case EOpAsinh:
2039 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2040 break;
2041
2042 case EOpAcosh:
2043 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2044 if (operandArray[i].getFConst() < 1.0f)
2045 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2046 diagnostics, &resultArray[i]);
2047 else
2048 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2049 break;
2050
2051 case EOpAtanh:
2052 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2053 // 0.
2054 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2055 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2056 diagnostics, &resultArray[i]);
2057 else
2058 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2059 break;
2060
2061 case EOpAbs:
2062 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302063 {
Olli Etuahof119a262016-08-19 15:54:22 +03002064 case EbtFloat:
2065 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2066 break;
2067 case EbtInt:
2068 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2069 break;
2070 default:
2071 UNREACHABLE();
2072 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302073 }
2074 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002075
2076 case EOpSign:
2077 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302078 {
Olli Etuahof119a262016-08-19 15:54:22 +03002079 case EbtFloat:
2080 {
2081 float fConst = operandArray[i].getFConst();
2082 float fResult = 0.0f;
2083 if (fConst > 0.0f)
2084 fResult = 1.0f;
2085 else if (fConst < 0.0f)
2086 fResult = -1.0f;
2087 resultArray[i].setFConst(fResult);
2088 break;
2089 }
2090 case EbtInt:
2091 {
2092 int iConst = operandArray[i].getIConst();
2093 int iResult = 0;
2094 if (iConst > 0)
2095 iResult = 1;
2096 else if (iConst < 0)
2097 iResult = -1;
2098 resultArray[i].setIConst(iResult);
2099 break;
2100 }
2101 default:
2102 UNREACHABLE();
2103 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302104 }
2105 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302106
Olli Etuahof119a262016-08-19 15:54:22 +03002107 case EOpFloor:
2108 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2109 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302110
Olli Etuahof119a262016-08-19 15:54:22 +03002111 case EOpTrunc:
2112 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2113 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302114
Olli Etuahof119a262016-08-19 15:54:22 +03002115 case EOpRound:
2116 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2117 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302118
Olli Etuahof119a262016-08-19 15:54:22 +03002119 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302120 {
Olli Etuahof119a262016-08-19 15:54:22 +03002121 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302122 float x = operandArray[i].getFConst();
2123 float result;
2124 float fractPart = modff(x, &result);
2125 if (fabsf(fractPart) == 0.5f)
2126 result = 2.0f * roundf(x / 2.0f);
2127 else
2128 result = roundf(x);
2129 resultArray[i].setFConst(result);
2130 break;
2131 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302132
Olli Etuahof119a262016-08-19 15:54:22 +03002133 case EOpCeil:
2134 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2135 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136
Olli Etuahof119a262016-08-19 15:54:22 +03002137 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302138 {
Olli Etuahof119a262016-08-19 15:54:22 +03002139 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302140 float x = operandArray[i].getFConst();
2141 resultArray[i].setFConst(x - floorf(x));
2142 break;
2143 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302144
Olli Etuahof119a262016-08-19 15:54:22 +03002145 case EOpIsNan:
2146 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302147 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2148 break;
Arun Patole551279e2015-07-07 18:18:23 +05302149
Olli Etuahof119a262016-08-19 15:54:22 +03002150 case EOpIsInf:
2151 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302152 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2153 break;
Arun Patole551279e2015-07-07 18:18:23 +05302154
Olli Etuahof119a262016-08-19 15:54:22 +03002155 case EOpFloatBitsToInt:
2156 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302157 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2158 break;
Arun Patole551279e2015-07-07 18:18:23 +05302159
Olli Etuahof119a262016-08-19 15:54:22 +03002160 case EOpFloatBitsToUint:
2161 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302162 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2163 break;
Arun Patole551279e2015-07-07 18:18:23 +05302164
Olli Etuahof119a262016-08-19 15:54:22 +03002165 case EOpIntBitsToFloat:
2166 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302167 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2168 break;
Arun Patole551279e2015-07-07 18:18:23 +05302169
Olli Etuahof119a262016-08-19 15:54:22 +03002170 case EOpUintBitsToFloat:
2171 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302172 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2173 break;
Arun Patole551279e2015-07-07 18:18:23 +05302174
Olli Etuahof119a262016-08-19 15:54:22 +03002175 case EOpExp:
2176 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2177 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302178
Olli Etuahof119a262016-08-19 15:54:22 +03002179 case EOpLog:
2180 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2181 if (operandArray[i].getFConst() <= 0.0f)
2182 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2183 diagnostics, &resultArray[i]);
2184 else
2185 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2186 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302187
Olli Etuahof119a262016-08-19 15:54:22 +03002188 case EOpExp2:
2189 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2190 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302191
Olli Etuahof119a262016-08-19 15:54:22 +03002192 case EOpLog2:
2193 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2194 // And log2f is not available on some plarforms like old android, so just using
2195 // log(x)/log(2) here.
2196 if (operandArray[i].getFConst() <= 0.0f)
2197 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2198 diagnostics, &resultArray[i]);
2199 else
2200 {
2201 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2202 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2203 }
2204 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302205
Olli Etuahof119a262016-08-19 15:54:22 +03002206 case EOpSqrt:
2207 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2208 if (operandArray[i].getFConst() < 0.0f)
2209 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2210 diagnostics, &resultArray[i]);
2211 else
2212 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2213 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302214
Olli Etuahof119a262016-08-19 15:54:22 +03002215 case EOpInverseSqrt:
2216 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2217 // so getting the square root first using builtin function sqrt() and then taking
2218 // its inverse.
2219 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2220 // result to 0.
2221 if (operandArray[i].getFConst() <= 0.0f)
2222 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2223 diagnostics, &resultArray[i]);
2224 else
2225 {
2226 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2227 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2228 }
2229 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302230
Olli Etuahod68924e2017-01-02 17:34:40 +00002231 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002232 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302233 resultArray[i].setBConst(!operandArray[i].getBConst());
2234 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302235
Olli Etuahof119a262016-08-19 15:54:22 +03002236 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302237 {
Olli Etuahof119a262016-08-19 15:54:22 +03002238 ASSERT(getType().getBasicType() == EbtFloat);
2239 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302240 float length = VectorLength(operandArray, objectSize);
2241 if (length)
2242 resultArray[i].setFConst(x / length);
2243 else
Olli Etuahof119a262016-08-19 15:54:22 +03002244 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2245 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302246 break;
2247 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002248 case EOpBitfieldReverse:
2249 {
2250 uint32_t value;
2251 if (getType().getBasicType() == EbtInt)
2252 {
2253 value = static_cast<uint32_t>(operandArray[i].getIConst());
2254 }
2255 else
2256 {
2257 ASSERT(getType().getBasicType() == EbtUInt);
2258 value = operandArray[i].getUConst();
2259 }
2260 uint32_t result = gl::BitfieldReverse(value);
2261 if (getType().getBasicType() == EbtInt)
2262 {
2263 resultArray[i].setIConst(static_cast<int32_t>(result));
2264 }
2265 else
2266 {
2267 resultArray[i].setUConst(result);
2268 }
2269 break;
2270 }
2271 case EOpBitCount:
2272 {
2273 uint32_t value;
2274 if (getType().getBasicType() == EbtInt)
2275 {
2276 value = static_cast<uint32_t>(operandArray[i].getIConst());
2277 }
2278 else
2279 {
2280 ASSERT(getType().getBasicType() == EbtUInt);
2281 value = operandArray[i].getUConst();
2282 }
2283 int result = gl::BitCount(value);
2284 resultArray[i].setIConst(result);
2285 break;
2286 }
2287 case EOpFindLSB:
2288 {
2289 uint32_t value;
2290 if (getType().getBasicType() == EbtInt)
2291 {
2292 value = static_cast<uint32_t>(operandArray[i].getIConst());
2293 }
2294 else
2295 {
2296 ASSERT(getType().getBasicType() == EbtUInt);
2297 value = operandArray[i].getUConst();
2298 }
2299 resultArray[i].setIConst(gl::FindLSB(value));
2300 break;
2301 }
2302 case EOpFindMSB:
2303 {
2304 uint32_t value;
2305 if (getType().getBasicType() == EbtInt)
2306 {
2307 int intValue = operandArray[i].getIConst();
2308 value = static_cast<uint32_t>(intValue);
2309 if (intValue < 0)
2310 {
2311 // Look for zero instead of one in value. This also handles the intValue ==
2312 // -1 special case, where the return value needs to be -1.
2313 value = ~value;
2314 }
2315 }
2316 else
2317 {
2318 ASSERT(getType().getBasicType() == EbtUInt);
2319 value = operandArray[i].getUConst();
2320 }
2321 resultArray[i].setIConst(gl::FindMSB(value));
2322 break;
2323 }
Olli Etuahof119a262016-08-19 15:54:22 +03002324 case EOpDFdx:
2325 case EOpDFdy:
2326 case EOpFwidth:
2327 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302328 // Derivatives of constant arguments should be 0.
2329 resultArray[i].setFConst(0.0f);
2330 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302331
Olli Etuahof119a262016-08-19 15:54:22 +03002332 default:
2333 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302334 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302335 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002336
Arun Patoleab2b9a22015-07-06 18:27:56 +05302337 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002338}
2339
Olli Etuahof119a262016-08-19 15:54:22 +03002340void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2341 FloatTypeUnaryFunc builtinFunc,
2342 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302343{
2344 ASSERT(builtinFunc);
2345
Olli Etuahof119a262016-08-19 15:54:22 +03002346 ASSERT(getType().getBasicType() == EbtFloat);
2347 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302348}
2349
Jamie Madillb1a85f42014-08-19 15:23:24 -04002350// static
Olli Etuahof119a262016-08-19 15:54:22 +03002351TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002352{
2353 ASSERT(aggregate->getSequence()->size() > 0u);
2354 size_t resultSize = aggregate->getType().getObjectSize();
2355 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2356 TBasicType basicType = aggregate->getBasicType();
2357
2358 size_t resultIndex = 0u;
2359
2360 if (aggregate->getSequence()->size() == 1u)
2361 {
2362 TIntermNode *argument = aggregate->getSequence()->front();
2363 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2364 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2365 // Check the special case of constructing a matrix diagonal from a single scalar,
2366 // or a vector from a single scalar.
2367 if (argumentConstant->getType().getObjectSize() == 1u)
2368 {
2369 if (aggregate->isMatrix())
2370 {
2371 int resultCols = aggregate->getType().getCols();
2372 int resultRows = aggregate->getType().getRows();
2373 for (int col = 0; col < resultCols; ++col)
2374 {
2375 for (int row = 0; row < resultRows; ++row)
2376 {
2377 if (col == row)
2378 {
2379 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2380 }
2381 else
2382 {
2383 resultArray[resultIndex].setFConst(0.0f);
2384 }
2385 ++resultIndex;
2386 }
2387 }
2388 }
2389 else
2390 {
2391 while (resultIndex < resultSize)
2392 {
2393 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2394 ++resultIndex;
2395 }
2396 }
2397 ASSERT(resultIndex == resultSize);
2398 return resultArray;
2399 }
2400 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2401 {
2402 // The special case of constructing a matrix from a matrix.
2403 int argumentCols = argumentConstant->getType().getCols();
2404 int argumentRows = argumentConstant->getType().getRows();
2405 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002406 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002407 for (int col = 0; col < resultCols; ++col)
2408 {
2409 for (int row = 0; row < resultRows; ++row)
2410 {
2411 if (col < argumentCols && row < argumentRows)
2412 {
2413 resultArray[resultIndex].cast(basicType,
2414 argumentUnionArray[col * argumentRows + row]);
2415 }
2416 else if (col == row)
2417 {
2418 resultArray[resultIndex].setFConst(1.0f);
2419 }
2420 else
2421 {
2422 resultArray[resultIndex].setFConst(0.0f);
2423 }
2424 ++resultIndex;
2425 }
2426 }
2427 ASSERT(resultIndex == resultSize);
2428 return resultArray;
2429 }
2430 }
2431
2432 for (TIntermNode *&argument : *aggregate->getSequence())
2433 {
2434 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2435 size_t argumentSize = argumentConstant->getType().getObjectSize();
2436 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2437 for (size_t i = 0u; i < argumentSize; ++i)
2438 {
2439 if (resultIndex >= resultSize)
2440 break;
2441 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2442 ++resultIndex;
2443 }
2444 }
2445 ASSERT(resultIndex == resultSize);
2446 return resultArray;
2447}
2448
2449// static
Olli Etuahof119a262016-08-19 15:54:22 +03002450TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2451 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302452{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002453 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002454 TIntermSequence *arguments = aggregate->getSequence();
2455 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2456 std::vector<const TConstantUnion *> unionArrays(argsCount);
2457 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002458 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302459 TBasicType basicType = EbtVoid;
2460 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002461 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302462 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002463 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2464 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302465
2466 if (i == 0)
2467 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002468 basicType = argConstant->getType().getBasicType();
2469 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302470 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002471 unionArrays[i] = argConstant->getUnionArrayPointer();
2472 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002473 if (objectSizes[i] > maxObjectSize)
2474 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302475 }
2476
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002477 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302478 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002479 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302480 if (objectSizes[i] != maxObjectSize)
2481 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2482 }
Arun Patole274f0702015-05-05 13:33:30 +05302483
Olli Etuahob43846e2015-06-02 18:18:57 +03002484 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002485
2486 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302487 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002488 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302489 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002490 ASSERT(basicType == EbtFloat);
2491 resultArray = new TConstantUnion[maxObjectSize];
2492 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302493 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002494 float y = unionArrays[0][i].getFConst();
2495 float x = unionArrays[1][i].getFConst();
2496 // Results are undefined if x and y are both 0.
2497 if (x == 0.0f && y == 0.0f)
2498 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2499 else
2500 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302501 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002502 break;
2503 }
Arun Patolebf790422015-05-18 17:53:04 +05302504
Olli Etuaho51182ab2017-01-22 00:12:29 +00002505 case EOpPow:
2506 {
2507 ASSERT(basicType == EbtFloat);
2508 resultArray = new TConstantUnion[maxObjectSize];
2509 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302510 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002511 float x = unionArrays[0][i].getFConst();
2512 float y = unionArrays[1][i].getFConst();
2513 // Results are undefined if x < 0.
2514 // Results are undefined if x = 0 and y <= 0.
2515 if (x < 0.0f)
2516 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2517 else if (x == 0.0f && y <= 0.0f)
2518 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2519 else
2520 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302521 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002522 break;
2523 }
Arun Patolebf790422015-05-18 17:53:04 +05302524
Olli Etuaho51182ab2017-01-22 00:12:29 +00002525 case EOpMod:
2526 {
2527 ASSERT(basicType == EbtFloat);
2528 resultArray = new TConstantUnion[maxObjectSize];
2529 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302530 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002531 float x = unionArrays[0][i].getFConst();
2532 float y = unionArrays[1][i].getFConst();
2533 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302534 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002535 break;
2536 }
Arun Patolebf790422015-05-18 17:53:04 +05302537
Olli Etuaho51182ab2017-01-22 00:12:29 +00002538 case EOpMin:
2539 {
2540 resultArray = new TConstantUnion[maxObjectSize];
2541 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302542 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002543 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302544 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002545 case EbtFloat:
2546 resultArray[i].setFConst(
2547 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2548 break;
2549 case EbtInt:
2550 resultArray[i].setIConst(
2551 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2552 break;
2553 case EbtUInt:
2554 resultArray[i].setUConst(
2555 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2556 break;
2557 default:
2558 UNREACHABLE();
2559 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302560 }
2561 }
2562 break;
Arun Patole274f0702015-05-05 13:33:30 +05302563 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002564
2565 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302566 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002567 resultArray = new TConstantUnion[maxObjectSize];
2568 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302569 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002570 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302571 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002572 case EbtFloat:
2573 resultArray[i].setFConst(
2574 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2575 break;
2576 case EbtInt:
2577 resultArray[i].setIConst(
2578 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2579 break;
2580 case EbtUInt:
2581 resultArray[i].setUConst(
2582 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2583 break;
2584 default:
2585 UNREACHABLE();
2586 break;
Arun Patole274f0702015-05-05 13:33:30 +05302587 }
2588 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002589 break;
Arun Patole274f0702015-05-05 13:33:30 +05302590 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002591
2592 case EOpStep:
2593 {
2594 ASSERT(basicType == EbtFloat);
2595 resultArray = new TConstantUnion[maxObjectSize];
2596 for (size_t i = 0; i < maxObjectSize; i++)
2597 resultArray[i].setFConst(
2598 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2599 break;
2600 }
2601
2602 case EOpLessThanComponentWise:
2603 {
2604 resultArray = new TConstantUnion[maxObjectSize];
2605 for (size_t i = 0; i < maxObjectSize; i++)
2606 {
2607 switch (basicType)
2608 {
2609 case EbtFloat:
2610 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2611 unionArrays[1][i].getFConst());
2612 break;
2613 case EbtInt:
2614 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2615 unionArrays[1][i].getIConst());
2616 break;
2617 case EbtUInt:
2618 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2619 unionArrays[1][i].getUConst());
2620 break;
2621 default:
2622 UNREACHABLE();
2623 break;
2624 }
2625 }
2626 break;
2627 }
2628
2629 case EOpLessThanEqualComponentWise:
2630 {
2631 resultArray = new TConstantUnion[maxObjectSize];
2632 for (size_t i = 0; i < maxObjectSize; i++)
2633 {
2634 switch (basicType)
2635 {
2636 case EbtFloat:
2637 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2638 unionArrays[1][i].getFConst());
2639 break;
2640 case EbtInt:
2641 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2642 unionArrays[1][i].getIConst());
2643 break;
2644 case EbtUInt:
2645 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2646 unionArrays[1][i].getUConst());
2647 break;
2648 default:
2649 UNREACHABLE();
2650 break;
2651 }
2652 }
2653 break;
2654 }
2655
2656 case EOpGreaterThanComponentWise:
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 case EOpGreaterThanEqualComponentWise:
2683 {
2684 resultArray = new TConstantUnion[maxObjectSize];
2685 for (size_t i = 0; i < maxObjectSize; i++)
2686 {
2687 switch (basicType)
2688 {
2689 case EbtFloat:
2690 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2691 unionArrays[1][i].getFConst());
2692 break;
2693 case EbtInt:
2694 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2695 unionArrays[1][i].getIConst());
2696 break;
2697 case EbtUInt:
2698 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2699 unionArrays[1][i].getUConst());
2700 break;
2701 default:
2702 UNREACHABLE();
2703 break;
2704 }
2705 }
2706 }
2707 break;
2708
2709 case EOpEqualComponentWise:
2710 {
2711 resultArray = new TConstantUnion[maxObjectSize];
2712 for (size_t i = 0; i < maxObjectSize; i++)
2713 {
2714 switch (basicType)
2715 {
2716 case EbtFloat:
2717 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2718 unionArrays[1][i].getFConst());
2719 break;
2720 case EbtInt:
2721 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2722 unionArrays[1][i].getIConst());
2723 break;
2724 case EbtUInt:
2725 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2726 unionArrays[1][i].getUConst());
2727 break;
2728 case EbtBool:
2729 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2730 unionArrays[1][i].getBConst());
2731 break;
2732 default:
2733 UNREACHABLE();
2734 break;
2735 }
2736 }
2737 break;
2738 }
2739
2740 case EOpNotEqualComponentWise:
2741 {
2742 resultArray = new TConstantUnion[maxObjectSize];
2743 for (size_t i = 0; i < maxObjectSize; i++)
2744 {
2745 switch (basicType)
2746 {
2747 case EbtFloat:
2748 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2749 unionArrays[1][i].getFConst());
2750 break;
2751 case EbtInt:
2752 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2753 unionArrays[1][i].getIConst());
2754 break;
2755 case EbtUInt:
2756 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2757 unionArrays[1][i].getUConst());
2758 break;
2759 case EbtBool:
2760 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2761 unionArrays[1][i].getBConst());
2762 break;
2763 default:
2764 UNREACHABLE();
2765 break;
2766 }
2767 }
2768 break;
2769 }
2770
2771 case EOpDistance:
2772 {
2773 ASSERT(basicType == EbtFloat);
2774 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2775 resultArray = new TConstantUnion();
2776 for (size_t i = 0; i < maxObjectSize; i++)
2777 {
2778 float x = unionArrays[0][i].getFConst();
2779 float y = unionArrays[1][i].getFConst();
2780 distanceArray[i].setFConst(x - y);
2781 }
2782 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2783 break;
2784 }
2785
2786 case EOpDot:
2787 ASSERT(basicType == EbtFloat);
2788 resultArray = new TConstantUnion();
2789 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2790 break;
2791
2792 case EOpCross:
2793 {
2794 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2795 resultArray = new TConstantUnion[maxObjectSize];
2796 float x0 = unionArrays[0][0].getFConst();
2797 float x1 = unionArrays[0][1].getFConst();
2798 float x2 = unionArrays[0][2].getFConst();
2799 float y0 = unionArrays[1][0].getFConst();
2800 float y1 = unionArrays[1][1].getFConst();
2801 float y2 = unionArrays[1][2].getFConst();
2802 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2803 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2804 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2805 break;
2806 }
2807
2808 case EOpReflect:
2809 {
2810 ASSERT(basicType == EbtFloat);
2811 // genType reflect (genType I, genType N) :
2812 // For the incident vector I and surface orientation N, returns the reflection
2813 // direction:
2814 // I - 2 * dot(N, I) * N.
2815 resultArray = new TConstantUnion[maxObjectSize];
2816 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2817 for (size_t i = 0; i < maxObjectSize; i++)
2818 {
2819 float result = unionArrays[0][i].getFConst() -
2820 2.0f * dotProduct * unionArrays[1][i].getFConst();
2821 resultArray[i].setFConst(result);
2822 }
2823 break;
2824 }
2825
2826 case EOpMulMatrixComponentWise:
2827 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002828 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
2829 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00002830 // Perform component-wise matrix multiplication.
2831 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002832 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002833 angle::Matrix<float> result =
2834 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2835 SetUnionArrayFromMatrix(result, resultArray);
2836 break;
2837 }
2838
2839 case EOpOuterProduct:
2840 {
2841 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002842 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
2843 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002844 resultArray = new TConstantUnion[numRows * numCols];
2845 angle::Matrix<float> result =
2846 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2847 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
2848 SetUnionArrayFromMatrix(result, resultArray);
2849 break;
2850 }
2851
2852 case EOpClamp:
2853 {
2854 resultArray = new TConstantUnion[maxObjectSize];
2855 for (size_t i = 0; i < maxObjectSize; i++)
2856 {
2857 switch (basicType)
2858 {
2859 case EbtFloat:
2860 {
2861 float x = unionArrays[0][i].getFConst();
2862 float min = unionArrays[1][i].getFConst();
2863 float max = unionArrays[2][i].getFConst();
2864 // Results are undefined if min > max.
2865 if (min > max)
2866 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2867 &resultArray[i]);
2868 else
2869 resultArray[i].setFConst(gl::clamp(x, min, max));
2870 break;
2871 }
2872
2873 case EbtInt:
2874 {
2875 int x = unionArrays[0][i].getIConst();
2876 int min = unionArrays[1][i].getIConst();
2877 int max = unionArrays[2][i].getIConst();
2878 // Results are undefined if min > max.
2879 if (min > max)
2880 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2881 &resultArray[i]);
2882 else
2883 resultArray[i].setIConst(gl::clamp(x, min, max));
2884 break;
2885 }
2886 case EbtUInt:
2887 {
2888 unsigned int x = unionArrays[0][i].getUConst();
2889 unsigned int min = unionArrays[1][i].getUConst();
2890 unsigned int max = unionArrays[2][i].getUConst();
2891 // Results are undefined if min > max.
2892 if (min > max)
2893 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2894 &resultArray[i]);
2895 else
2896 resultArray[i].setUConst(gl::clamp(x, min, max));
2897 break;
2898 }
2899 default:
2900 UNREACHABLE();
2901 break;
2902 }
2903 }
2904 break;
2905 }
2906
2907 case EOpMix:
2908 {
2909 ASSERT(basicType == EbtFloat);
2910 resultArray = new TConstantUnion[maxObjectSize];
2911 for (size_t i = 0; i < maxObjectSize; i++)
2912 {
2913 float x = unionArrays[0][i].getFConst();
2914 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002915 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002916 if (type == EbtFloat)
2917 {
2918 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2919 float a = unionArrays[2][i].getFConst();
2920 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2921 }
2922 else // 3rd parameter is EbtBool
2923 {
2924 ASSERT(type == EbtBool);
2925 // Selects which vector each returned component comes from.
2926 // For a component of a that is false, the corresponding component of x is
2927 // returned.
2928 // For a component of a that is true, the corresponding component of y is
2929 // returned.
2930 bool a = unionArrays[2][i].getBConst();
2931 resultArray[i].setFConst(a ? y : x);
2932 }
2933 }
2934 break;
2935 }
2936
2937 case EOpSmoothStep:
2938 {
2939 ASSERT(basicType == EbtFloat);
2940 resultArray = new TConstantUnion[maxObjectSize];
2941 for (size_t i = 0; i < maxObjectSize; i++)
2942 {
2943 float edge0 = unionArrays[0][i].getFConst();
2944 float edge1 = unionArrays[1][i].getFConst();
2945 float x = unionArrays[2][i].getFConst();
2946 // Results are undefined if edge0 >= edge1.
2947 if (edge0 >= edge1)
2948 {
2949 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2950 }
2951 else
2952 {
2953 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2954 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2955 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2956 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
2957 }
2958 }
2959 break;
2960 }
2961
2962 case EOpFaceForward:
2963 {
2964 ASSERT(basicType == EbtFloat);
2965 // genType faceforward(genType N, genType I, genType Nref) :
2966 // If dot(Nref, I) < 0 return N, otherwise return -N.
2967 resultArray = new TConstantUnion[maxObjectSize];
2968 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2969 for (size_t i = 0; i < maxObjectSize; i++)
2970 {
2971 if (dotProduct < 0)
2972 resultArray[i].setFConst(unionArrays[0][i].getFConst());
2973 else
2974 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
2975 }
2976 break;
2977 }
2978
2979 case EOpRefract:
2980 {
2981 ASSERT(basicType == EbtFloat);
2982 // genType refract(genType I, genType N, float eta) :
2983 // For the incident vector I and surface normal N, and the ratio of indices of
2984 // refraction eta,
2985 // return the refraction vector. The result is computed by
2986 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2987 // if (k < 0.0)
2988 // return genType(0.0)
2989 // else
2990 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
2991 resultArray = new TConstantUnion[maxObjectSize];
2992 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2993 for (size_t i = 0; i < maxObjectSize; i++)
2994 {
2995 float eta = unionArrays[2][i].getFConst();
2996 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2997 if (k < 0.0f)
2998 resultArray[i].setFConst(0.0f);
2999 else
3000 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3001 (eta * dotProduct + sqrtf(k)) *
3002 unionArrays[1][i].getFConst());
3003 }
3004 break;
3005 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003006 case EOpBitfieldExtract:
3007 {
3008 resultArray = new TConstantUnion[maxObjectSize];
3009 for (size_t i = 0; i < maxObjectSize; ++i)
3010 {
3011 int offset = unionArrays[1][0].getIConst();
3012 int bits = unionArrays[2][0].getIConst();
3013 if (bits == 0)
3014 {
3015 if (aggregate->getBasicType() == EbtInt)
3016 {
3017 resultArray[i].setIConst(0);
3018 }
3019 else
3020 {
3021 ASSERT(aggregate->getBasicType() == EbtUInt);
3022 resultArray[i].setUConst(0);
3023 }
3024 }
3025 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3026 {
3027 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3028 &resultArray[i]);
3029 }
3030 else
3031 {
3032 // bits can be 32 here, so we need to avoid bit shift overflow.
3033 uint32_t maskMsb = 1u << (bits - 1);
3034 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3035 if (aggregate->getBasicType() == EbtInt)
3036 {
3037 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3038 uint32_t resultUnsigned = (value & mask) >> offset;
3039 if ((resultUnsigned & maskMsb) != 0)
3040 {
3041 // The most significant bits (from bits+1 to the most significant bit)
3042 // should be set to 1.
3043 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3044 resultUnsigned |= higherBitsMask;
3045 }
3046 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3047 }
3048 else
3049 {
3050 ASSERT(aggregate->getBasicType() == EbtUInt);
3051 uint32_t value = unionArrays[0][i].getUConst();
3052 resultArray[i].setUConst((value & mask) >> offset);
3053 }
3054 }
3055 }
3056 break;
3057 }
3058 case EOpBitfieldInsert:
3059 {
3060 resultArray = new TConstantUnion[maxObjectSize];
3061 for (size_t i = 0; i < maxObjectSize; ++i)
3062 {
3063 int offset = unionArrays[2][0].getIConst();
3064 int bits = unionArrays[3][0].getIConst();
3065 if (bits == 0)
3066 {
3067 if (aggregate->getBasicType() == EbtInt)
3068 {
3069 int32_t base = unionArrays[0][i].getIConst();
3070 resultArray[i].setIConst(base);
3071 }
3072 else
3073 {
3074 ASSERT(aggregate->getBasicType() == EbtUInt);
3075 uint32_t base = unionArrays[0][i].getUConst();
3076 resultArray[i].setUConst(base);
3077 }
3078 }
3079 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3080 {
3081 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3082 &resultArray[i]);
3083 }
3084 else
3085 {
3086 // bits can be 32 here, so we need to avoid bit shift overflow.
3087 uint32_t maskMsb = 1u << (bits - 1);
3088 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3089 uint32_t baseMask = ~insertMask;
3090 if (aggregate->getBasicType() == EbtInt)
3091 {
3092 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3093 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3094 uint32_t resultUnsigned =
3095 (base & baseMask) | ((insert << offset) & insertMask);
3096 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3097 }
3098 else
3099 {
3100 ASSERT(aggregate->getBasicType() == EbtUInt);
3101 uint32_t base = unionArrays[0][i].getUConst();
3102 uint32_t insert = unionArrays[1][i].getUConst();
3103 resultArray[i].setUConst((base & baseMask) |
3104 ((insert << offset) & insertMask));
3105 }
3106 }
3107 }
3108 break;
3109 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003110
3111 default:
3112 UNREACHABLE();
3113 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303114 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003115 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303116}
3117
3118// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04003119TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
3120{
3121 if (hashFunction == NULL || name.empty())
3122 return name;
3123 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
3124 TStringStream stream;
3125 stream << HASHED_NAME_PREFIX << std::hex << number;
3126 TString hashedName = stream.str();
3127 return hashedName;
3128}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003129
3130void TIntermTraverser::updateTree()
3131{
Olli Etuahoa6f22092015-05-08 18:31:10 +03003132 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
3133 {
3134 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
3135 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003136 if (!insertion.insertionsAfter.empty())
3137 {
3138 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
3139 insertion.insertionsAfter);
3140 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003141 }
3142 if (!insertion.insertionsBefore.empty())
3143 {
3144 bool inserted =
3145 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
3146 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003147 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03003148 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003149 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
3150 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003151 const NodeUpdateEntry &replacement = mReplacements[ii];
3152 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003153 bool replaced =
3154 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003155 ASSERT(replaced);
3156
Olli Etuahocd94ef92015-04-16 19:18:10 +03003157 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003158 {
3159 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03003160 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003161 // be replaced, we need to make sure we don't update the replaced
3162 // node; instead, we update the replacement node.
3163 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
3164 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003165 NodeUpdateEntry &replacement2 = mReplacements[jj];
3166 if (replacement2.parent == replacement.original)
3167 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003168 }
3169 }
3170 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003171 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
3172 {
3173 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
3174 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003175 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
3176 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003177 ASSERT(replaced);
3178 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03003179
Jamie Madill03d863c2016-07-27 18:15:53 -04003180 clearReplacementQueue();
3181}
3182
3183void TIntermTraverser::clearReplacementQueue()
3184{
Olli Etuahod4f303e2015-05-20 17:09:06 +03003185 mReplacements.clear();
3186 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04003187 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003188}
Jamie Madill1048e432016-07-23 18:51:28 -04003189
Jamie Madill03d863c2016-07-27 18:15:53 -04003190void TIntermTraverser::queueReplacement(TIntermNode *original,
3191 TIntermNode *replacement,
3192 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003193{
Jamie Madill03d863c2016-07-27 18:15:53 -04003194 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04003195}
3196
Jamie Madill03d863c2016-07-27 18:15:53 -04003197void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
3198 TIntermNode *original,
3199 TIntermNode *replacement,
3200 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003201{
Jamie Madill03d863c2016-07-27 18:15:53 -04003202 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
3203 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04003204}
Jamie Madill45bcc782016-11-07 13:58:48 -05003205
3206} // namespace sh