blob: 403930538fe1962fc776b432c045b34bf148db3c [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:
Olli Etuaho25aef452017-01-29 16:15:44 -0800824 case EOpPackUnorm4x8:
825 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300826 setType(TType(EbtUInt, EbpHigh, resultQualifier));
827 break;
828 case EOpUnpackSnorm2x16:
829 case EOpUnpackUnorm2x16:
830 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
831 break;
832 case EOpUnpackHalf2x16:
833 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
834 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800835 case EOpUnpackUnorm4x8:
836 case EOpUnpackSnorm4x8:
837 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
838 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300839 case EOpAny:
840 case EOpAll:
841 setType(TType(EbtBool, EbpUndefined, resultQualifier));
842 break;
843 case EOpLength:
844 case EOpDeterminant:
845 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
846 break;
847 case EOpTranspose:
848 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
849 static_cast<unsigned char>(mOperand->getType().getRows()),
850 static_cast<unsigned char>(mOperand->getType().getCols())));
851 break;
852 case EOpIsInf:
853 case EOpIsNan:
854 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
855 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000856 case EOpBitfieldReverse:
857 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
858 break;
859 case EOpBitCount:
860 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
861 break;
862 case EOpFindLSB:
863 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
864 break;
865 case EOpFindMSB:
866 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
867 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300868 default:
869 setType(mOperand->getType());
870 mType.setQualifier(resultQualifier);
871 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400872 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300873}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400874
Olli Etuahob6fa0432016-09-28 16:28:05 +0100875TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
876 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
877 mOperand(operand),
878 mSwizzleOffsets(swizzleOffsets)
879{
880 ASSERT(mSwizzleOffsets.size() <= 4);
881 promote();
882}
883
Olli Etuahoa2234302016-08-31 12:05:39 +0300884TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
885 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
886{
887 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400888}
889
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300890TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
891 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
892{
893 promote();
894}
895
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000896TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
897 : TIntermNode(), mSymbol(symbol)
898{
899 ASSERT(symbol);
900 setLine(line);
901}
902
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300903TIntermTernary::TIntermTernary(TIntermTyped *cond,
904 TIntermTyped *trueExpression,
905 TIntermTyped *falseExpression)
906 : TIntermTyped(trueExpression->getType()),
907 mCondition(cond),
908 mTrueExpression(trueExpression),
909 mFalseExpression(falseExpression)
910{
911 getTypePointer()->setQualifier(
912 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
913}
914
915// static
916TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
917 TIntermTyped *trueExpression,
918 TIntermTyped *falseExpression)
919{
920 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
921 falseExpression->getQualifier() == EvqConst)
922 {
923 return EvqConst;
924 }
925 return EvqTemporary;
926}
927
Olli Etuahob6fa0432016-09-28 16:28:05 +0100928void TIntermSwizzle::promote()
929{
930 TQualifier resultQualifier = EvqTemporary;
931 if (mOperand->getQualifier() == EvqConst)
932 resultQualifier = EvqConst;
933
934 auto numFields = mSwizzleOffsets.size();
935 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
936 static_cast<unsigned char>(numFields)));
937}
938
939bool TIntermSwizzle::hasDuplicateOffsets() const
940{
941 int offsetCount[4] = {0u, 0u, 0u, 0u};
942 for (const auto offset : mSwizzleOffsets)
943 {
944 offsetCount[offset]++;
945 if (offsetCount[offset] > 1)
946 {
947 return true;
948 }
949 }
950 return false;
951}
952
Olli Etuaho09b04a22016-12-15 13:30:26 +0000953bool TIntermSwizzle::offsetsMatch(int offset) const
954{
955 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
956}
957
Olli Etuahob6fa0432016-09-28 16:28:05 +0100958void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
959{
960 for (const int offset : mSwizzleOffsets)
961 {
962 switch (offset)
963 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500964 case 0:
965 *out << "x";
966 break;
967 case 1:
968 *out << "y";
969 break;
970 case 2:
971 *out << "z";
972 break;
973 case 3:
974 *out << "w";
975 break;
976 default:
977 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +0100978 }
979 }
980}
981
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100982TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
983 const TIntermTyped *left,
984 const TIntermTyped *right)
985{
986 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
987 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
988 right->getQualifier() != EvqConst)
989 {
990 return EvqTemporary;
991 }
992 return EvqConst;
993}
Olli Etuahob6fa0432016-09-28 16:28:05 +0100994
995// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300996void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400997{
Olli Etuaho1dded802016-08-18 18:13:13 +0300998 ASSERT(!isMultiplication() ||
999 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1000
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001001 // Comma is handled as a special case.
1002 if (mOp == EOpComma)
1003 {
1004 setType(mRight->getType());
1005 return;
1006 }
1007
Jamie Madillb1a85f42014-08-19 15:23:24 -04001008 // Base assumption: just make the type the same as the left
1009 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001010 setType(mLeft->getType());
1011
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001012 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001013 // Binary operations results in temporary variables unless both
1014 // operands are const.
1015 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1016 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001017 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001018 getTypePointer()->setQualifier(EvqTemporary);
1019 }
1020
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001021 // Handle indexing ops.
1022 switch (mOp)
1023 {
1024 case EOpIndexDirect:
1025 case EOpIndexIndirect:
1026 if (mLeft->isArray())
1027 {
1028 mType.clearArrayness();
1029 }
1030 else if (mLeft->isMatrix())
1031 {
1032 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1033 static_cast<unsigned char>(mLeft->getRows())));
1034 }
1035 else if (mLeft->isVector())
1036 {
1037 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1038 }
1039 else
1040 {
1041 UNREACHABLE();
1042 }
1043 return;
1044 case EOpIndexDirectStruct:
1045 {
1046 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1047 const int i = mRight->getAsConstantUnion()->getIConst(0);
1048 setType(*fields[i]->type());
1049 getTypePointer()->setQualifier(resultQualifier);
1050 return;
1051 }
1052 case EOpIndexDirectInterfaceBlock:
1053 {
1054 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1055 const int i = mRight->getAsConstantUnion()->getIConst(0);
1056 setType(*fields[i]->type());
1057 getTypePointer()->setQualifier(resultQualifier);
1058 return;
1059 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001060 default:
1061 break;
1062 }
1063
1064 ASSERT(mLeft->isArray() == mRight->isArray());
1065
1066 // The result gets promoted to the highest precision.
1067 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1068 getTypePointer()->setPrecision(higherPrecision);
1069
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001070 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001071
1072 //
1073 // All scalars or structs. Code after this test assumes this case is removed!
1074 //
1075 if (nominalSize == 1)
1076 {
1077 switch (mOp)
1078 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001079 //
1080 // Promote to conditional
1081 //
1082 case EOpEqual:
1083 case EOpNotEqual:
1084 case EOpLessThan:
1085 case EOpGreaterThan:
1086 case EOpLessThanEqual:
1087 case EOpGreaterThanEqual:
1088 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1089 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001090
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001091 //
1092 // And and Or operate on conditionals
1093 //
1094 case EOpLogicalAnd:
1095 case EOpLogicalXor:
1096 case EOpLogicalOr:
1097 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1098 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1099 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001100
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001101 default:
1102 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001103 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001104 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001105 }
1106
1107 // If we reach here, at least one of the operands is vector or matrix.
1108 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001109 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001110
Jamie Madillb1a85f42014-08-19 15:23:24 -04001111 switch (mOp)
1112 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001113 case EOpMul:
1114 break;
1115 case EOpMatrixTimesScalar:
1116 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001117 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001118 setType(TType(basicType, higherPrecision, resultQualifier,
1119 static_cast<unsigned char>(mRight->getCols()),
1120 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001121 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001122 break;
1123 case EOpMatrixTimesVector:
1124 setType(TType(basicType, higherPrecision, resultQualifier,
1125 static_cast<unsigned char>(mLeft->getRows()), 1));
1126 break;
1127 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001128 setType(TType(basicType, higherPrecision, resultQualifier,
1129 static_cast<unsigned char>(mRight->getCols()),
1130 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001131 break;
1132 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001133 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001134 static_cast<unsigned char>(nominalSize), 1));
1135 break;
1136 case EOpVectorTimesMatrix:
1137 setType(TType(basicType, higherPrecision, resultQualifier,
1138 static_cast<unsigned char>(mRight->getCols()), 1));
1139 break;
1140 case EOpMulAssign:
1141 case EOpVectorTimesScalarAssign:
1142 case EOpVectorTimesMatrixAssign:
1143 case EOpMatrixTimesScalarAssign:
1144 case EOpMatrixTimesMatrixAssign:
1145 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1146 break;
1147 case EOpAssign:
1148 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001149 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1150 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1151 break;
1152 case EOpAdd:
1153 case EOpSub:
1154 case EOpDiv:
1155 case EOpIMod:
1156 case EOpBitShiftLeft:
1157 case EOpBitShiftRight:
1158 case EOpBitwiseAnd:
1159 case EOpBitwiseXor:
1160 case EOpBitwiseOr:
1161 case EOpAddAssign:
1162 case EOpSubAssign:
1163 case EOpDivAssign:
1164 case EOpIModAssign:
1165 case EOpBitShiftLeftAssign:
1166 case EOpBitShiftRightAssign:
1167 case EOpBitwiseAndAssign:
1168 case EOpBitwiseXorAssign:
1169 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001170 {
1171 const int secondarySize =
1172 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1173 setType(TType(basicType, higherPrecision, resultQualifier,
1174 static_cast<unsigned char>(nominalSize),
1175 static_cast<unsigned char>(secondarySize)));
1176 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001177 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001178 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001179 case EOpEqual:
1180 case EOpNotEqual:
1181 case EOpLessThan:
1182 case EOpGreaterThan:
1183 case EOpLessThanEqual:
1184 case EOpGreaterThanEqual:
1185 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1186 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001187 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001188 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001189
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001190 case EOpIndexDirect:
1191 case EOpIndexIndirect:
1192 case EOpIndexDirectInterfaceBlock:
1193 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001194 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001195 UNREACHABLE();
1196 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001197 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001198 UNREACHABLE();
1199 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001200 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001201}
1202
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001203const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001204{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001205 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001206 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001207 ASSERT(index < static_cast<int>(getType().getArraySize()));
1208 TType arrayElementType = getType();
1209 arrayElementType.clearArrayness();
1210 size_t arrayElementSize = arrayElementType.getObjectSize();
1211 return &mUnionArrayPointer[arrayElementSize * index];
1212 }
1213 else if (isMatrix())
1214 {
1215 ASSERT(index < getType().getCols());
1216 int size = getType().getRows();
1217 return &mUnionArrayPointer[size * index];
1218 }
1219 else if (isVector())
1220 {
1221 ASSERT(index < getType().getNominalSize());
1222 return &mUnionArrayPointer[index];
1223 }
1224 else
1225 {
1226 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001227 return nullptr;
1228 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001229}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001230
Olli Etuahob6fa0432016-09-28 16:28:05 +01001231TIntermTyped *TIntermSwizzle::fold()
1232{
1233 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1234 if (operandConstant == nullptr)
1235 {
1236 return nullptr;
1237 }
1238
1239 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1240 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1241 {
1242 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1243 }
1244 return CreateFoldedNode(constArray, this, mType.getQualifier());
1245}
1246
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001247TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1248{
1249 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1250 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1251 switch (mOp)
1252 {
1253 case EOpIndexDirect:
1254 {
1255 if (leftConstant == nullptr || rightConstant == nullptr)
1256 {
1257 return nullptr;
1258 }
1259 int index = rightConstant->getIConst(0);
1260
1261 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1262 return CreateFoldedNode(constArray, this, mType.getQualifier());
1263 }
1264 case EOpIndexDirectStruct:
1265 {
1266 if (leftConstant == nullptr || rightConstant == nullptr)
1267 {
1268 return nullptr;
1269 }
1270 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1271 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1272
1273 size_t previousFieldsSize = 0;
1274 for (size_t i = 0; i < index; ++i)
1275 {
1276 previousFieldsSize += fields[i]->type()->getObjectSize();
1277 }
1278
1279 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1280 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1281 }
1282 case EOpIndexIndirect:
1283 case EOpIndexDirectInterfaceBlock:
1284 // Can never be constant folded.
1285 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001286 default:
1287 {
1288 if (leftConstant == nullptr || rightConstant == nullptr)
1289 {
1290 return nullptr;
1291 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001292 TConstantUnion *constArray =
1293 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001294
1295 // Nodes may be constant folded without being qualified as constant.
1296 return CreateFoldedNode(constArray, this, mType.getQualifier());
1297 }
1298 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001299}
1300
Olli Etuahof119a262016-08-19 15:54:22 +03001301TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001302{
1303 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1304 if (operandConstant == nullptr)
1305 {
1306 return nullptr;
1307 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301308
1309 TConstantUnion *constArray = nullptr;
1310 switch (mOp)
1311 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001312 case EOpAny:
1313 case EOpAll:
1314 case EOpLength:
1315 case EOpTranspose:
1316 case EOpDeterminant:
1317 case EOpInverse:
1318 case EOpPackSnorm2x16:
1319 case EOpUnpackSnorm2x16:
1320 case EOpPackUnorm2x16:
1321 case EOpUnpackUnorm2x16:
1322 case EOpPackHalf2x16:
1323 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001324 case EOpPackUnorm4x8:
1325 case EOpPackSnorm4x8:
1326 case EOpUnpackUnorm4x8:
1327 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001328 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1329 break;
1330 default:
1331 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1332 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301333 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001334
1335 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001336 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001337}
1338
Olli Etuahof119a262016-08-19 15:54:22 +03001339TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001340{
1341 // Make sure that all params are constant before actual constant folding.
1342 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001343 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001344 if (param->getAsConstantUnion() == nullptr)
1345 {
1346 return nullptr;
1347 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001348 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001349 TConstantUnion *constArray = nullptr;
1350 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001351 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001352 else
Olli Etuahof119a262016-08-19 15:54:22 +03001353 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001354
1355 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001356 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001357}
1358
Jamie Madillb1a85f42014-08-19 15:23:24 -04001359//
1360// The fold functions see if an operation on a constant can be done in place,
1361// without generating run-time code.
1362//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001363// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001364//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001365TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1366 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001367 TDiagnostics *diagnostics,
1368 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001369{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001370 const TConstantUnion *leftArray = getUnionArrayPointer();
1371 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001372
Olli Etuahof119a262016-08-19 15:54:22 +03001373 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001374
1375 size_t objectSize = getType().getObjectSize();
1376
1377 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1378 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1379 {
1380 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1381 }
1382 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1383 {
1384 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001385 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001386 objectSize = rightNode->getType().getObjectSize();
1387 }
1388
1389 TConstantUnion *resultArray = nullptr;
1390
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001391 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001392 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001393 case EOpAdd:
1394 resultArray = new TConstantUnion[objectSize];
1395 for (size_t i = 0; i < objectSize; i++)
1396 resultArray[i] =
1397 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1398 break;
1399 case EOpSub:
1400 resultArray = new TConstantUnion[objectSize];
1401 for (size_t i = 0; i < objectSize; i++)
1402 resultArray[i] =
1403 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1404 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001405
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001406 case EOpMul:
1407 case EOpVectorTimesScalar:
1408 case EOpMatrixTimesScalar:
1409 resultArray = new TConstantUnion[objectSize];
1410 for (size_t i = 0; i < objectSize; i++)
1411 resultArray[i] =
1412 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1413 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001414
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001415 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001416 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001417 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001418 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001419
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001420 const int leftCols = getCols();
1421 const int leftRows = getRows();
1422 const int rightCols = rightNode->getType().getCols();
1423 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001424 const int resultCols = rightCols;
1425 const int resultRows = leftRows;
1426
1427 resultArray = new TConstantUnion[resultCols * resultRows];
1428 for (int row = 0; row < resultRows; row++)
1429 {
1430 for (int column = 0; column < resultCols; column++)
1431 {
1432 resultArray[resultRows * column + row].setFConst(0.0f);
1433 for (int i = 0; i < leftCols; i++)
1434 {
1435 resultArray[resultRows * column + row].setFConst(
1436 resultArray[resultRows * column + row].getFConst() +
1437 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001438 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001439 }
1440 }
1441 }
1442 }
1443 break;
1444
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001445 case EOpDiv:
1446 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001447 {
1448 resultArray = new TConstantUnion[objectSize];
1449 for (size_t i = 0; i < objectSize; i++)
1450 {
1451 switch (getType().getBasicType())
1452 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001453 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001454 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001455 ASSERT(op == EOpDiv);
1456 float dividend = leftArray[i].getFConst();
1457 float divisor = rightArray[i].getFConst();
1458 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001459 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001460 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001461 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001462 diagnostics->warning(
1463 getLine(),
1464 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001465 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001466 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001467 }
1468 else
1469 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001470 diagnostics->warning(getLine(),
1471 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001472 bool negativeResult =
1473 std::signbit(dividend) != std::signbit(divisor);
1474 resultArray[i].setFConst(
1475 negativeResult ? -std::numeric_limits<float>::infinity()
1476 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001477 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001478 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001479 else if (gl::isInf(dividend) && gl::isInf(divisor))
1480 {
1481 diagnostics->warning(getLine(),
1482 "Infinity divided by infinity during constant "
1483 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001484 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001485 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1486 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001487 else
1488 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001489 float result = dividend / divisor;
1490 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001491 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001492 diagnostics->warning(
1493 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001494 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001495 }
1496 resultArray[i].setFConst(result);
1497 }
1498 break;
1499 }
1500 case EbtInt:
1501 if (rightArray[i] == 0)
1502 {
1503 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001504 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001505 resultArray[i].setIConst(INT_MAX);
1506 }
1507 else
1508 {
1509 int lhs = leftArray[i].getIConst();
1510 int divisor = rightArray[i].getIConst();
1511 if (op == EOpDiv)
1512 {
1513 // Check for the special case where the minimum representable number
1514 // is
1515 // divided by -1. If left alone this leads to integer overflow in
1516 // C++.
1517 // ESSL 3.00.6 section 4.1.3 Integers:
1518 // "However, for the case where the minimum representable value is
1519 // divided by -1, it is allowed to return either the minimum
1520 // representable value or the maximum representable value."
1521 if (lhs == -0x7fffffff - 1 && divisor == -1)
1522 {
1523 resultArray[i].setIConst(0x7fffffff);
1524 }
1525 else
1526 {
1527 resultArray[i].setIConst(lhs / divisor);
1528 }
Olli Etuahod4453572016-09-27 13:21:46 +01001529 }
1530 else
1531 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001532 ASSERT(op == EOpIMod);
1533 if (lhs < 0 || divisor < 0)
1534 {
1535 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1536 // when
1537 // either one of the operands is negative.
1538 diagnostics->warning(getLine(),
1539 "Negative modulus operator operand "
1540 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001541 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001542 resultArray[i].setIConst(0);
1543 }
1544 else
1545 {
1546 resultArray[i].setIConst(lhs % divisor);
1547 }
Olli Etuahod4453572016-09-27 13:21:46 +01001548 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001549 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001550 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001551
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001552 case EbtUInt:
1553 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001554 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001555 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001556 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001557 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001558 }
1559 else
1560 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001561 if (op == EOpDiv)
1562 {
1563 resultArray[i].setUConst(leftArray[i].getUConst() /
1564 rightArray[i].getUConst());
1565 }
1566 else
1567 {
1568 ASSERT(op == EOpIMod);
1569 resultArray[i].setUConst(leftArray[i].getUConst() %
1570 rightArray[i].getUConst());
1571 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001572 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001573 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001574
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001575 default:
1576 UNREACHABLE();
1577 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001578 }
1579 }
1580 }
1581 break;
1582
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001583 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001584 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001585 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001586 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001587
1588 const int matrixCols = getCols();
1589 const int matrixRows = getRows();
1590
1591 resultArray = new TConstantUnion[matrixRows];
1592
1593 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1594 {
1595 resultArray[matrixRow].setFConst(0.0f);
1596 for (int col = 0; col < matrixCols; col++)
1597 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001598 resultArray[matrixRow].setFConst(
1599 resultArray[matrixRow].getFConst() +
1600 leftArray[col * matrixRows + matrixRow].getFConst() *
1601 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001602 }
1603 }
1604 }
1605 break;
1606
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001607 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001608 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001609 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001610 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001611
1612 const int matrixCols = rightNode->getType().getCols();
1613 const int matrixRows = rightNode->getType().getRows();
1614
1615 resultArray = new TConstantUnion[matrixCols];
1616
1617 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1618 {
1619 resultArray[matrixCol].setFConst(0.0f);
1620 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1621 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001622 resultArray[matrixCol].setFConst(
1623 resultArray[matrixCol].getFConst() +
1624 leftArray[matrixRow].getFConst() *
1625 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001626 }
1627 }
1628 }
1629 break;
1630
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001631 case EOpLogicalAnd:
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 EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001642 {
1643 resultArray = new TConstantUnion[objectSize];
1644 for (size_t i = 0; i < objectSize; i++)
1645 {
1646 resultArray[i] = leftArray[i] || rightArray[i];
1647 }
1648 }
1649 break;
1650
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001651 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001652 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001653 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001654 resultArray = new TConstantUnion[objectSize];
1655 for (size_t i = 0; i < objectSize; i++)
1656 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001657 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001658 }
1659 }
1660 break;
1661
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001662 case EOpBitwiseAnd:
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 EOpBitwiseXor:
1668 resultArray = new TConstantUnion[objectSize];
1669 for (size_t i = 0; i < objectSize; i++)
1670 resultArray[i] = leftArray[i] ^ rightArray[i];
1671 break;
1672 case EOpBitwiseOr:
1673 resultArray = new TConstantUnion[objectSize];
1674 for (size_t i = 0; i < objectSize; i++)
1675 resultArray[i] = leftArray[i] | rightArray[i];
1676 break;
1677 case EOpBitShiftLeft:
1678 resultArray = new TConstantUnion[objectSize];
1679 for (size_t i = 0; i < objectSize; i++)
1680 resultArray[i] =
1681 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1682 break;
1683 case EOpBitShiftRight:
1684 resultArray = new TConstantUnion[objectSize];
1685 for (size_t i = 0; i < objectSize; i++)
1686 resultArray[i] =
1687 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1688 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001689
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001690 case EOpLessThan:
1691 ASSERT(objectSize == 1);
1692 resultArray = new TConstantUnion[1];
1693 resultArray->setBConst(*leftArray < *rightArray);
1694 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001695
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001696 case EOpGreaterThan:
1697 ASSERT(objectSize == 1);
1698 resultArray = new TConstantUnion[1];
1699 resultArray->setBConst(*leftArray > *rightArray);
1700 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001701
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001702 case EOpLessThanEqual:
1703 ASSERT(objectSize == 1);
1704 resultArray = new TConstantUnion[1];
1705 resultArray->setBConst(!(*leftArray > *rightArray));
1706 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001707
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001708 case EOpGreaterThanEqual:
1709 ASSERT(objectSize == 1);
1710 resultArray = new TConstantUnion[1];
1711 resultArray->setBConst(!(*leftArray < *rightArray));
1712 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001713
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001714 case EOpEqual:
1715 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001716 {
1717 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001718 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001719 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001720 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001721 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001722 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001723 equal = false;
1724 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001725 }
1726 }
1727 if (op == EOpEqual)
1728 {
1729 resultArray->setBConst(equal);
1730 }
1731 else
1732 {
1733 resultArray->setBConst(!equal);
1734 }
1735 }
1736 break;
1737
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001738 default:
1739 UNREACHABLE();
1740 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001741 }
1742 return resultArray;
1743}
1744
Olli Etuahof119a262016-08-19 15:54:22 +03001745// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1746// code. Returns the constant value to keep using. Nullptr should not be returned.
1747TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001748{
Olli Etuahof119a262016-08-19 15:54:22 +03001749 // Do operations where the return type may have a different number of components compared to the
1750 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001751
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001752 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001753 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301754
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001755 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301756 TConstantUnion *resultArray = nullptr;
1757 switch (op)
1758 {
Olli Etuahof119a262016-08-19 15:54:22 +03001759 case EOpAny:
1760 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301761 resultArray = new TConstantUnion();
1762 resultArray->setBConst(false);
1763 for (size_t i = 0; i < objectSize; i++)
1764 {
1765 if (operandArray[i].getBConst())
1766 {
1767 resultArray->setBConst(true);
1768 break;
1769 }
1770 }
1771 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301772
Olli Etuahof119a262016-08-19 15:54:22 +03001773 case EOpAll:
1774 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301775 resultArray = new TConstantUnion();
1776 resultArray->setBConst(true);
1777 for (size_t i = 0; i < objectSize; i++)
1778 {
1779 if (!operandArray[i].getBConst())
1780 {
1781 resultArray->setBConst(false);
1782 break;
1783 }
1784 }
1785 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301786
Olli Etuahof119a262016-08-19 15:54:22 +03001787 case EOpLength:
1788 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301789 resultArray = new TConstantUnion();
1790 resultArray->setFConst(VectorLength(operandArray, objectSize));
1791 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301792
Olli Etuahof119a262016-08-19 15:54:22 +03001793 case EOpTranspose:
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 resultArray = new TConstantUnion[objectSize];
1797 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001798 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301799 SetUnionArrayFromMatrix(result, resultArray);
1800 break;
1801 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301802
Olli Etuahof119a262016-08-19 15:54:22 +03001803 case EOpDeterminant:
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);
1808 resultArray = new TConstantUnion();
1809 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1810 break;
1811 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301812
Olli Etuahof119a262016-08-19 15:54:22 +03001813 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301814 {
Olli Etuahof119a262016-08-19 15:54:22 +03001815 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301816 unsigned int size = getType().getNominalSize();
1817 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001818 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301819 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1820 SetUnionArrayFromMatrix(result, resultArray);
1821 break;
1822 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301823
Olli Etuahof119a262016-08-19 15:54:22 +03001824 case EOpPackSnorm2x16:
1825 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301826 ASSERT(getType().getNominalSize() == 2);
1827 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001828 resultArray->setUConst(
1829 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301830 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301831
Olli Etuahof119a262016-08-19 15:54:22 +03001832 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301833 {
Olli Etuahof119a262016-08-19 15:54:22 +03001834 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301835 resultArray = new TConstantUnion[2];
1836 float f1, f2;
1837 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1838 resultArray[0].setFConst(f1);
1839 resultArray[1].setFConst(f2);
1840 break;
1841 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301842
Olli Etuahof119a262016-08-19 15:54:22 +03001843 case EOpPackUnorm2x16:
1844 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301845 ASSERT(getType().getNominalSize() == 2);
1846 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001847 resultArray->setUConst(
1848 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301849 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301850
Olli Etuahof119a262016-08-19 15:54:22 +03001851 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301852 {
Olli Etuahof119a262016-08-19 15:54:22 +03001853 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301854 resultArray = new TConstantUnion[2];
1855 float f1, f2;
1856 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1857 resultArray[0].setFConst(f1);
1858 resultArray[1].setFConst(f2);
1859 break;
1860 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301861
Olli Etuahof119a262016-08-19 15:54:22 +03001862 case EOpPackHalf2x16:
1863 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301864 ASSERT(getType().getNominalSize() == 2);
1865 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001866 resultArray->setUConst(
1867 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301868 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301869
Olli Etuahof119a262016-08-19 15:54:22 +03001870 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301871 {
Olli Etuahof119a262016-08-19 15:54:22 +03001872 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301873 resultArray = new TConstantUnion[2];
1874 float f1, f2;
1875 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1876 resultArray[0].setFConst(f1);
1877 resultArray[1].setFConst(f2);
1878 break;
1879 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301880
Olli Etuaho25aef452017-01-29 16:15:44 -08001881 case EOpPackUnorm4x8:
1882 {
1883 ASSERT(getType().getBasicType() == EbtFloat);
1884 resultArray = new TConstantUnion();
1885 resultArray->setUConst(
1886 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1887 operandArray[2].getFConst(), operandArray[3].getFConst()));
1888 break;
1889 }
1890 case EOpPackSnorm4x8:
1891 {
1892 ASSERT(getType().getBasicType() == EbtFloat);
1893 resultArray = new TConstantUnion();
1894 resultArray->setUConst(
1895 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1896 operandArray[2].getFConst(), operandArray[3].getFConst()));
1897 break;
1898 }
1899 case EOpUnpackUnorm4x8:
1900 {
1901 ASSERT(getType().getBasicType() == EbtUInt);
1902 resultArray = new TConstantUnion[4];
1903 float f[4];
1904 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
1905 for (size_t i = 0; i < 4; ++i)
1906 {
1907 resultArray[i].setFConst(f[i]);
1908 }
1909 break;
1910 }
1911 case EOpUnpackSnorm4x8:
1912 {
1913 ASSERT(getType().getBasicType() == EbtUInt);
1914 resultArray = new TConstantUnion[4];
1915 float f[4];
1916 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
1917 for (size_t i = 0; i < 4; ++i)
1918 {
1919 resultArray[i].setFConst(f[i]);
1920 }
1921 break;
1922 }
1923
Olli Etuahof119a262016-08-19 15:54:22 +03001924 default:
1925 UNREACHABLE();
1926 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301927 }
1928
1929 return resultArray;
1930}
1931
Olli Etuahof119a262016-08-19 15:54:22 +03001932TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1933 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301934{
Olli Etuahof119a262016-08-19 15:54:22 +03001935 // Do unary operations where each component of the result is computed based on the corresponding
1936 // component of the operand. Also folds normalize, though the divisor in that case takes all
1937 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301938
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001939 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001940 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001941
1942 size_t objectSize = getType().getObjectSize();
1943
Arun Patoleab2b9a22015-07-06 18:27:56 +05301944 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1945 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301946 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001947 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301948 {
Olli Etuahof119a262016-08-19 15:54:22 +03001949 case EOpNegative:
1950 switch (getType().getBasicType())
1951 {
1952 case EbtFloat:
1953 resultArray[i].setFConst(-operandArray[i].getFConst());
1954 break;
1955 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001956 if (operandArray[i] == std::numeric_limits<int>::min())
1957 {
1958 // The minimum representable integer doesn't have a positive
1959 // counterpart, rather the negation overflows and in ESSL is supposed to
1960 // wrap back to the minimum representable integer. Make sure that we
1961 // don't actually let the negation overflow, which has undefined
1962 // behavior in C++.
1963 resultArray[i].setIConst(std::numeric_limits<int>::min());
1964 }
1965 else
1966 {
1967 resultArray[i].setIConst(-operandArray[i].getIConst());
1968 }
Olli Etuahof119a262016-08-19 15:54:22 +03001969 break;
1970 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001971 if (operandArray[i] == 0x80000000u)
1972 {
1973 resultArray[i].setUConst(0x80000000u);
1974 }
1975 else
1976 {
1977 resultArray[i].setUConst(static_cast<unsigned int>(
1978 -static_cast<int>(operandArray[i].getUConst())));
1979 }
Olli Etuahof119a262016-08-19 15:54:22 +03001980 break;
1981 default:
1982 UNREACHABLE();
1983 return nullptr;
1984 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301985 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301986
Olli Etuahof119a262016-08-19 15:54:22 +03001987 case EOpPositive:
1988 switch (getType().getBasicType())
1989 {
1990 case EbtFloat:
1991 resultArray[i].setFConst(operandArray[i].getFConst());
1992 break;
1993 case EbtInt:
1994 resultArray[i].setIConst(operandArray[i].getIConst());
1995 break;
1996 case EbtUInt:
1997 resultArray[i].setUConst(static_cast<unsigned int>(
1998 static_cast<int>(operandArray[i].getUConst())));
1999 break;
2000 default:
2001 UNREACHABLE();
2002 return nullptr;
2003 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302004 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302005
Olli Etuahof119a262016-08-19 15:54:22 +03002006 case EOpLogicalNot:
2007 switch (getType().getBasicType())
2008 {
2009 case EbtBool:
2010 resultArray[i].setBConst(!operandArray[i].getBConst());
2011 break;
2012 default:
2013 UNREACHABLE();
2014 return nullptr;
2015 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302016 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302017
Olli Etuahof119a262016-08-19 15:54:22 +03002018 case EOpBitwiseNot:
2019 switch (getType().getBasicType())
2020 {
2021 case EbtInt:
2022 resultArray[i].setIConst(~operandArray[i].getIConst());
2023 break;
2024 case EbtUInt:
2025 resultArray[i].setUConst(~operandArray[i].getUConst());
2026 break;
2027 default:
2028 UNREACHABLE();
2029 return nullptr;
2030 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302031 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302032
Olli Etuahof119a262016-08-19 15:54:22 +03002033 case EOpRadians:
2034 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302035 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2036 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302037
Olli Etuahof119a262016-08-19 15:54:22 +03002038 case EOpDegrees:
2039 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302040 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2041 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302042
Olli Etuahof119a262016-08-19 15:54:22 +03002043 case EOpSin:
2044 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302045 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302046
Olli Etuahof119a262016-08-19 15:54:22 +03002047 case EOpCos:
2048 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2049 break;
2050
2051 case EOpTan:
2052 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2053 break;
2054
2055 case EOpAsin:
2056 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2057 // 0.
2058 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2059 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2060 diagnostics, &resultArray[i]);
2061 else
2062 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2063 break;
2064
2065 case EOpAcos:
2066 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2067 // 0.
2068 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2069 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2070 diagnostics, &resultArray[i]);
2071 else
2072 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2073 break;
2074
2075 case EOpAtan:
2076 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2077 break;
2078
2079 case EOpSinh:
2080 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2081 break;
2082
2083 case EOpCosh:
2084 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2085 break;
2086
2087 case EOpTanh:
2088 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2089 break;
2090
2091 case EOpAsinh:
2092 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2093 break;
2094
2095 case EOpAcosh:
2096 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2097 if (operandArray[i].getFConst() < 1.0f)
2098 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2099 diagnostics, &resultArray[i]);
2100 else
2101 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2102 break;
2103
2104 case EOpAtanh:
2105 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2106 // 0.
2107 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2108 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2109 diagnostics, &resultArray[i]);
2110 else
2111 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2112 break;
2113
2114 case EOpAbs:
2115 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302116 {
Olli Etuahof119a262016-08-19 15:54:22 +03002117 case EbtFloat:
2118 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2119 break;
2120 case EbtInt:
2121 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2122 break;
2123 default:
2124 UNREACHABLE();
2125 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302126 }
2127 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002128
2129 case EOpSign:
2130 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302131 {
Olli Etuahof119a262016-08-19 15:54:22 +03002132 case EbtFloat:
2133 {
2134 float fConst = operandArray[i].getFConst();
2135 float fResult = 0.0f;
2136 if (fConst > 0.0f)
2137 fResult = 1.0f;
2138 else if (fConst < 0.0f)
2139 fResult = -1.0f;
2140 resultArray[i].setFConst(fResult);
2141 break;
2142 }
2143 case EbtInt:
2144 {
2145 int iConst = operandArray[i].getIConst();
2146 int iResult = 0;
2147 if (iConst > 0)
2148 iResult = 1;
2149 else if (iConst < 0)
2150 iResult = -1;
2151 resultArray[i].setIConst(iResult);
2152 break;
2153 }
2154 default:
2155 UNREACHABLE();
2156 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302157 }
2158 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302159
Olli Etuahof119a262016-08-19 15:54:22 +03002160 case EOpFloor:
2161 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2162 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302163
Olli Etuahof119a262016-08-19 15:54:22 +03002164 case EOpTrunc:
2165 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2166 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302167
Olli Etuahof119a262016-08-19 15:54:22 +03002168 case EOpRound:
2169 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2170 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302171
Olli Etuahof119a262016-08-19 15:54:22 +03002172 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302173 {
Olli Etuahof119a262016-08-19 15:54:22 +03002174 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302175 float x = operandArray[i].getFConst();
2176 float result;
2177 float fractPart = modff(x, &result);
2178 if (fabsf(fractPart) == 0.5f)
2179 result = 2.0f * roundf(x / 2.0f);
2180 else
2181 result = roundf(x);
2182 resultArray[i].setFConst(result);
2183 break;
2184 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302185
Olli Etuahof119a262016-08-19 15:54:22 +03002186 case EOpCeil:
2187 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2188 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302189
Olli Etuahof119a262016-08-19 15:54:22 +03002190 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302191 {
Olli Etuahof119a262016-08-19 15:54:22 +03002192 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302193 float x = operandArray[i].getFConst();
2194 resultArray[i].setFConst(x - floorf(x));
2195 break;
2196 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302197
Olli Etuahof119a262016-08-19 15:54:22 +03002198 case EOpIsNan:
2199 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302200 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2201 break;
Arun Patole551279e2015-07-07 18:18:23 +05302202
Olli Etuahof119a262016-08-19 15:54:22 +03002203 case EOpIsInf:
2204 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302205 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2206 break;
Arun Patole551279e2015-07-07 18:18:23 +05302207
Olli Etuahof119a262016-08-19 15:54:22 +03002208 case EOpFloatBitsToInt:
2209 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302210 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2211 break;
Arun Patole551279e2015-07-07 18:18:23 +05302212
Olli Etuahof119a262016-08-19 15:54:22 +03002213 case EOpFloatBitsToUint:
2214 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302215 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2216 break;
Arun Patole551279e2015-07-07 18:18:23 +05302217
Olli Etuahof119a262016-08-19 15:54:22 +03002218 case EOpIntBitsToFloat:
2219 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302220 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2221 break;
Arun Patole551279e2015-07-07 18:18:23 +05302222
Olli Etuahof119a262016-08-19 15:54:22 +03002223 case EOpUintBitsToFloat:
2224 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302225 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2226 break;
Arun Patole551279e2015-07-07 18:18:23 +05302227
Olli Etuahof119a262016-08-19 15:54:22 +03002228 case EOpExp:
2229 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2230 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302231
Olli Etuahof119a262016-08-19 15:54:22 +03002232 case EOpLog:
2233 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2234 if (operandArray[i].getFConst() <= 0.0f)
2235 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2236 diagnostics, &resultArray[i]);
2237 else
2238 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2239 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302240
Olli Etuahof119a262016-08-19 15:54:22 +03002241 case EOpExp2:
2242 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2243 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302244
Olli Etuahof119a262016-08-19 15:54:22 +03002245 case EOpLog2:
2246 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2247 // And log2f is not available on some plarforms like old android, so just using
2248 // log(x)/log(2) here.
2249 if (operandArray[i].getFConst() <= 0.0f)
2250 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2251 diagnostics, &resultArray[i]);
2252 else
2253 {
2254 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2255 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2256 }
2257 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302258
Olli Etuahof119a262016-08-19 15:54:22 +03002259 case EOpSqrt:
2260 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2261 if (operandArray[i].getFConst() < 0.0f)
2262 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2263 diagnostics, &resultArray[i]);
2264 else
2265 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2266 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302267
Olli Etuahof119a262016-08-19 15:54:22 +03002268 case EOpInverseSqrt:
2269 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2270 // so getting the square root first using builtin function sqrt() and then taking
2271 // its inverse.
2272 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2273 // result to 0.
2274 if (operandArray[i].getFConst() <= 0.0f)
2275 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2276 diagnostics, &resultArray[i]);
2277 else
2278 {
2279 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2280 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2281 }
2282 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302283
Olli Etuahod68924e2017-01-02 17:34:40 +00002284 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002285 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302286 resultArray[i].setBConst(!operandArray[i].getBConst());
2287 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302288
Olli Etuahof119a262016-08-19 15:54:22 +03002289 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302290 {
Olli Etuahof119a262016-08-19 15:54:22 +03002291 ASSERT(getType().getBasicType() == EbtFloat);
2292 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302293 float length = VectorLength(operandArray, objectSize);
2294 if (length)
2295 resultArray[i].setFConst(x / length);
2296 else
Olli Etuahof119a262016-08-19 15:54:22 +03002297 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2298 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302299 break;
2300 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002301 case EOpBitfieldReverse:
2302 {
2303 uint32_t value;
2304 if (getType().getBasicType() == EbtInt)
2305 {
2306 value = static_cast<uint32_t>(operandArray[i].getIConst());
2307 }
2308 else
2309 {
2310 ASSERT(getType().getBasicType() == EbtUInt);
2311 value = operandArray[i].getUConst();
2312 }
2313 uint32_t result = gl::BitfieldReverse(value);
2314 if (getType().getBasicType() == EbtInt)
2315 {
2316 resultArray[i].setIConst(static_cast<int32_t>(result));
2317 }
2318 else
2319 {
2320 resultArray[i].setUConst(result);
2321 }
2322 break;
2323 }
2324 case EOpBitCount:
2325 {
2326 uint32_t value;
2327 if (getType().getBasicType() == EbtInt)
2328 {
2329 value = static_cast<uint32_t>(operandArray[i].getIConst());
2330 }
2331 else
2332 {
2333 ASSERT(getType().getBasicType() == EbtUInt);
2334 value = operandArray[i].getUConst();
2335 }
2336 int result = gl::BitCount(value);
2337 resultArray[i].setIConst(result);
2338 break;
2339 }
2340 case EOpFindLSB:
2341 {
2342 uint32_t value;
2343 if (getType().getBasicType() == EbtInt)
2344 {
2345 value = static_cast<uint32_t>(operandArray[i].getIConst());
2346 }
2347 else
2348 {
2349 ASSERT(getType().getBasicType() == EbtUInt);
2350 value = operandArray[i].getUConst();
2351 }
2352 resultArray[i].setIConst(gl::FindLSB(value));
2353 break;
2354 }
2355 case EOpFindMSB:
2356 {
2357 uint32_t value;
2358 if (getType().getBasicType() == EbtInt)
2359 {
2360 int intValue = operandArray[i].getIConst();
2361 value = static_cast<uint32_t>(intValue);
2362 if (intValue < 0)
2363 {
2364 // Look for zero instead of one in value. This also handles the intValue ==
2365 // -1 special case, where the return value needs to be -1.
2366 value = ~value;
2367 }
2368 }
2369 else
2370 {
2371 ASSERT(getType().getBasicType() == EbtUInt);
2372 value = operandArray[i].getUConst();
2373 }
2374 resultArray[i].setIConst(gl::FindMSB(value));
2375 break;
2376 }
Olli Etuahof119a262016-08-19 15:54:22 +03002377 case EOpDFdx:
2378 case EOpDFdy:
2379 case EOpFwidth:
2380 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302381 // Derivatives of constant arguments should be 0.
2382 resultArray[i].setFConst(0.0f);
2383 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302384
Olli Etuahof119a262016-08-19 15:54:22 +03002385 default:
2386 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302387 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302388 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002389
Arun Patoleab2b9a22015-07-06 18:27:56 +05302390 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002391}
2392
Olli Etuahof119a262016-08-19 15:54:22 +03002393void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2394 FloatTypeUnaryFunc builtinFunc,
2395 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302396{
2397 ASSERT(builtinFunc);
2398
Olli Etuahof119a262016-08-19 15:54:22 +03002399 ASSERT(getType().getBasicType() == EbtFloat);
2400 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302401}
2402
Jamie Madillb1a85f42014-08-19 15:23:24 -04002403// static
Olli Etuahof119a262016-08-19 15:54:22 +03002404TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002405{
2406 ASSERT(aggregate->getSequence()->size() > 0u);
2407 size_t resultSize = aggregate->getType().getObjectSize();
2408 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2409 TBasicType basicType = aggregate->getBasicType();
2410
2411 size_t resultIndex = 0u;
2412
2413 if (aggregate->getSequence()->size() == 1u)
2414 {
2415 TIntermNode *argument = aggregate->getSequence()->front();
2416 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2417 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2418 // Check the special case of constructing a matrix diagonal from a single scalar,
2419 // or a vector from a single scalar.
2420 if (argumentConstant->getType().getObjectSize() == 1u)
2421 {
2422 if (aggregate->isMatrix())
2423 {
2424 int resultCols = aggregate->getType().getCols();
2425 int resultRows = aggregate->getType().getRows();
2426 for (int col = 0; col < resultCols; ++col)
2427 {
2428 for (int row = 0; row < resultRows; ++row)
2429 {
2430 if (col == row)
2431 {
2432 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2433 }
2434 else
2435 {
2436 resultArray[resultIndex].setFConst(0.0f);
2437 }
2438 ++resultIndex;
2439 }
2440 }
2441 }
2442 else
2443 {
2444 while (resultIndex < resultSize)
2445 {
2446 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2447 ++resultIndex;
2448 }
2449 }
2450 ASSERT(resultIndex == resultSize);
2451 return resultArray;
2452 }
2453 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2454 {
2455 // The special case of constructing a matrix from a matrix.
2456 int argumentCols = argumentConstant->getType().getCols();
2457 int argumentRows = argumentConstant->getType().getRows();
2458 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002459 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002460 for (int col = 0; col < resultCols; ++col)
2461 {
2462 for (int row = 0; row < resultRows; ++row)
2463 {
2464 if (col < argumentCols && row < argumentRows)
2465 {
2466 resultArray[resultIndex].cast(basicType,
2467 argumentUnionArray[col * argumentRows + row]);
2468 }
2469 else if (col == row)
2470 {
2471 resultArray[resultIndex].setFConst(1.0f);
2472 }
2473 else
2474 {
2475 resultArray[resultIndex].setFConst(0.0f);
2476 }
2477 ++resultIndex;
2478 }
2479 }
2480 ASSERT(resultIndex == resultSize);
2481 return resultArray;
2482 }
2483 }
2484
2485 for (TIntermNode *&argument : *aggregate->getSequence())
2486 {
2487 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2488 size_t argumentSize = argumentConstant->getType().getObjectSize();
2489 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2490 for (size_t i = 0u; i < argumentSize; ++i)
2491 {
2492 if (resultIndex >= resultSize)
2493 break;
2494 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2495 ++resultIndex;
2496 }
2497 }
2498 ASSERT(resultIndex == resultSize);
2499 return resultArray;
2500}
2501
2502// static
Olli Etuahof119a262016-08-19 15:54:22 +03002503TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2504 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302505{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002506 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002507 TIntermSequence *arguments = aggregate->getSequence();
2508 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2509 std::vector<const TConstantUnion *> unionArrays(argsCount);
2510 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002511 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302512 TBasicType basicType = EbtVoid;
2513 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002514 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302515 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002516 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2517 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302518
2519 if (i == 0)
2520 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002521 basicType = argConstant->getType().getBasicType();
2522 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302523 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002524 unionArrays[i] = argConstant->getUnionArrayPointer();
2525 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002526 if (objectSizes[i] > maxObjectSize)
2527 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302528 }
2529
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002530 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302531 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002532 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302533 if (objectSizes[i] != maxObjectSize)
2534 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2535 }
Arun Patole274f0702015-05-05 13:33:30 +05302536
Olli Etuahob43846e2015-06-02 18:18:57 +03002537 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002538
2539 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302540 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002541 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302542 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002543 ASSERT(basicType == EbtFloat);
2544 resultArray = new TConstantUnion[maxObjectSize];
2545 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302546 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002547 float y = unionArrays[0][i].getFConst();
2548 float x = unionArrays[1][i].getFConst();
2549 // Results are undefined if x and y are both 0.
2550 if (x == 0.0f && y == 0.0f)
2551 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2552 else
2553 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302554 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002555 break;
2556 }
Arun Patolebf790422015-05-18 17:53:04 +05302557
Olli Etuaho51182ab2017-01-22 00:12:29 +00002558 case EOpPow:
2559 {
2560 ASSERT(basicType == EbtFloat);
2561 resultArray = new TConstantUnion[maxObjectSize];
2562 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302563 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002564 float x = unionArrays[0][i].getFConst();
2565 float y = unionArrays[1][i].getFConst();
2566 // Results are undefined if x < 0.
2567 // Results are undefined if x = 0 and y <= 0.
2568 if (x < 0.0f)
2569 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2570 else if (x == 0.0f && y <= 0.0f)
2571 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2572 else
2573 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302574 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002575 break;
2576 }
Arun Patolebf790422015-05-18 17:53:04 +05302577
Olli Etuaho51182ab2017-01-22 00:12:29 +00002578 case EOpMod:
2579 {
2580 ASSERT(basicType == EbtFloat);
2581 resultArray = new TConstantUnion[maxObjectSize];
2582 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302583 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002584 float x = unionArrays[0][i].getFConst();
2585 float y = unionArrays[1][i].getFConst();
2586 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302587 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002588 break;
2589 }
Arun Patolebf790422015-05-18 17:53:04 +05302590
Olli Etuaho51182ab2017-01-22 00:12:29 +00002591 case EOpMin:
2592 {
2593 resultArray = new TConstantUnion[maxObjectSize];
2594 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302595 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002596 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302597 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002598 case EbtFloat:
2599 resultArray[i].setFConst(
2600 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2601 break;
2602 case EbtInt:
2603 resultArray[i].setIConst(
2604 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2605 break;
2606 case EbtUInt:
2607 resultArray[i].setUConst(
2608 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2609 break;
2610 default:
2611 UNREACHABLE();
2612 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302613 }
2614 }
2615 break;
Arun Patole274f0702015-05-05 13:33:30 +05302616 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002617
2618 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302619 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002620 resultArray = new TConstantUnion[maxObjectSize];
2621 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302622 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002623 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302624 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002625 case EbtFloat:
2626 resultArray[i].setFConst(
2627 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2628 break;
2629 case EbtInt:
2630 resultArray[i].setIConst(
2631 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2632 break;
2633 case EbtUInt:
2634 resultArray[i].setUConst(
2635 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2636 break;
2637 default:
2638 UNREACHABLE();
2639 break;
Arun Patole274f0702015-05-05 13:33:30 +05302640 }
2641 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002642 break;
Arun Patole274f0702015-05-05 13:33:30 +05302643 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002644
2645 case EOpStep:
2646 {
2647 ASSERT(basicType == EbtFloat);
2648 resultArray = new TConstantUnion[maxObjectSize];
2649 for (size_t i = 0; i < maxObjectSize; i++)
2650 resultArray[i].setFConst(
2651 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2652 break;
2653 }
2654
2655 case EOpLessThanComponentWise:
2656 {
2657 resultArray = new TConstantUnion[maxObjectSize];
2658 for (size_t i = 0; i < maxObjectSize; i++)
2659 {
2660 switch (basicType)
2661 {
2662 case EbtFloat:
2663 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2664 unionArrays[1][i].getFConst());
2665 break;
2666 case EbtInt:
2667 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2668 unionArrays[1][i].getIConst());
2669 break;
2670 case EbtUInt:
2671 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2672 unionArrays[1][i].getUConst());
2673 break;
2674 default:
2675 UNREACHABLE();
2676 break;
2677 }
2678 }
2679 break;
2680 }
2681
2682 case EOpLessThanEqualComponentWise:
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 break;
2707 }
2708
2709 case EOpGreaterThanComponentWise:
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 default:
2729 UNREACHABLE();
2730 break;
2731 }
2732 }
2733 break;
2734 }
2735 case EOpGreaterThanEqualComponentWise:
2736 {
2737 resultArray = new TConstantUnion[maxObjectSize];
2738 for (size_t i = 0; i < maxObjectSize; i++)
2739 {
2740 switch (basicType)
2741 {
2742 case EbtFloat:
2743 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2744 unionArrays[1][i].getFConst());
2745 break;
2746 case EbtInt:
2747 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2748 unionArrays[1][i].getIConst());
2749 break;
2750 case EbtUInt:
2751 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2752 unionArrays[1][i].getUConst());
2753 break;
2754 default:
2755 UNREACHABLE();
2756 break;
2757 }
2758 }
2759 }
2760 break;
2761
2762 case EOpEqualComponentWise:
2763 {
2764 resultArray = new TConstantUnion[maxObjectSize];
2765 for (size_t i = 0; i < maxObjectSize; i++)
2766 {
2767 switch (basicType)
2768 {
2769 case EbtFloat:
2770 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2771 unionArrays[1][i].getFConst());
2772 break;
2773 case EbtInt:
2774 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2775 unionArrays[1][i].getIConst());
2776 break;
2777 case EbtUInt:
2778 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2779 unionArrays[1][i].getUConst());
2780 break;
2781 case EbtBool:
2782 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2783 unionArrays[1][i].getBConst());
2784 break;
2785 default:
2786 UNREACHABLE();
2787 break;
2788 }
2789 }
2790 break;
2791 }
2792
2793 case EOpNotEqualComponentWise:
2794 {
2795 resultArray = new TConstantUnion[maxObjectSize];
2796 for (size_t i = 0; i < maxObjectSize; i++)
2797 {
2798 switch (basicType)
2799 {
2800 case EbtFloat:
2801 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2802 unionArrays[1][i].getFConst());
2803 break;
2804 case EbtInt:
2805 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2806 unionArrays[1][i].getIConst());
2807 break;
2808 case EbtUInt:
2809 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2810 unionArrays[1][i].getUConst());
2811 break;
2812 case EbtBool:
2813 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2814 unionArrays[1][i].getBConst());
2815 break;
2816 default:
2817 UNREACHABLE();
2818 break;
2819 }
2820 }
2821 break;
2822 }
2823
2824 case EOpDistance:
2825 {
2826 ASSERT(basicType == EbtFloat);
2827 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2828 resultArray = new TConstantUnion();
2829 for (size_t i = 0; i < maxObjectSize; i++)
2830 {
2831 float x = unionArrays[0][i].getFConst();
2832 float y = unionArrays[1][i].getFConst();
2833 distanceArray[i].setFConst(x - y);
2834 }
2835 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2836 break;
2837 }
2838
2839 case EOpDot:
2840 ASSERT(basicType == EbtFloat);
2841 resultArray = new TConstantUnion();
2842 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2843 break;
2844
2845 case EOpCross:
2846 {
2847 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2848 resultArray = new TConstantUnion[maxObjectSize];
2849 float x0 = unionArrays[0][0].getFConst();
2850 float x1 = unionArrays[0][1].getFConst();
2851 float x2 = unionArrays[0][2].getFConst();
2852 float y0 = unionArrays[1][0].getFConst();
2853 float y1 = unionArrays[1][1].getFConst();
2854 float y2 = unionArrays[1][2].getFConst();
2855 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2856 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2857 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2858 break;
2859 }
2860
2861 case EOpReflect:
2862 {
2863 ASSERT(basicType == EbtFloat);
2864 // genType reflect (genType I, genType N) :
2865 // For the incident vector I and surface orientation N, returns the reflection
2866 // direction:
2867 // I - 2 * dot(N, I) * N.
2868 resultArray = new TConstantUnion[maxObjectSize];
2869 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2870 for (size_t i = 0; i < maxObjectSize; i++)
2871 {
2872 float result = unionArrays[0][i].getFConst() -
2873 2.0f * dotProduct * unionArrays[1][i].getFConst();
2874 resultArray[i].setFConst(result);
2875 }
2876 break;
2877 }
2878
2879 case EOpMulMatrixComponentWise:
2880 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002881 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
2882 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00002883 // Perform component-wise matrix multiplication.
2884 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002885 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002886 angle::Matrix<float> result =
2887 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2888 SetUnionArrayFromMatrix(result, resultArray);
2889 break;
2890 }
2891
2892 case EOpOuterProduct:
2893 {
2894 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002895 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
2896 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002897 resultArray = new TConstantUnion[numRows * numCols];
2898 angle::Matrix<float> result =
2899 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2900 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
2901 SetUnionArrayFromMatrix(result, resultArray);
2902 break;
2903 }
2904
2905 case EOpClamp:
2906 {
2907 resultArray = new TConstantUnion[maxObjectSize];
2908 for (size_t i = 0; i < maxObjectSize; i++)
2909 {
2910 switch (basicType)
2911 {
2912 case EbtFloat:
2913 {
2914 float x = unionArrays[0][i].getFConst();
2915 float min = unionArrays[1][i].getFConst();
2916 float max = unionArrays[2][i].getFConst();
2917 // Results are undefined if min > max.
2918 if (min > max)
2919 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2920 &resultArray[i]);
2921 else
2922 resultArray[i].setFConst(gl::clamp(x, min, max));
2923 break;
2924 }
2925
2926 case EbtInt:
2927 {
2928 int x = unionArrays[0][i].getIConst();
2929 int min = unionArrays[1][i].getIConst();
2930 int max = unionArrays[2][i].getIConst();
2931 // Results are undefined if min > max.
2932 if (min > max)
2933 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2934 &resultArray[i]);
2935 else
2936 resultArray[i].setIConst(gl::clamp(x, min, max));
2937 break;
2938 }
2939 case EbtUInt:
2940 {
2941 unsigned int x = unionArrays[0][i].getUConst();
2942 unsigned int min = unionArrays[1][i].getUConst();
2943 unsigned int max = unionArrays[2][i].getUConst();
2944 // Results are undefined if min > max.
2945 if (min > max)
2946 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2947 &resultArray[i]);
2948 else
2949 resultArray[i].setUConst(gl::clamp(x, min, max));
2950 break;
2951 }
2952 default:
2953 UNREACHABLE();
2954 break;
2955 }
2956 }
2957 break;
2958 }
2959
2960 case EOpMix:
2961 {
2962 ASSERT(basicType == EbtFloat);
2963 resultArray = new TConstantUnion[maxObjectSize];
2964 for (size_t i = 0; i < maxObjectSize; i++)
2965 {
2966 float x = unionArrays[0][i].getFConst();
2967 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002968 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002969 if (type == EbtFloat)
2970 {
2971 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2972 float a = unionArrays[2][i].getFConst();
2973 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2974 }
2975 else // 3rd parameter is EbtBool
2976 {
2977 ASSERT(type == EbtBool);
2978 // Selects which vector each returned component comes from.
2979 // For a component of a that is false, the corresponding component of x is
2980 // returned.
2981 // For a component of a that is true, the corresponding component of y is
2982 // returned.
2983 bool a = unionArrays[2][i].getBConst();
2984 resultArray[i].setFConst(a ? y : x);
2985 }
2986 }
2987 break;
2988 }
2989
2990 case EOpSmoothStep:
2991 {
2992 ASSERT(basicType == EbtFloat);
2993 resultArray = new TConstantUnion[maxObjectSize];
2994 for (size_t i = 0; i < maxObjectSize; i++)
2995 {
2996 float edge0 = unionArrays[0][i].getFConst();
2997 float edge1 = unionArrays[1][i].getFConst();
2998 float x = unionArrays[2][i].getFConst();
2999 // Results are undefined if edge0 >= edge1.
3000 if (edge0 >= edge1)
3001 {
3002 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3003 }
3004 else
3005 {
3006 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3007 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3008 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3009 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3010 }
3011 }
3012 break;
3013 }
3014
3015 case EOpFaceForward:
3016 {
3017 ASSERT(basicType == EbtFloat);
3018 // genType faceforward(genType N, genType I, genType Nref) :
3019 // If dot(Nref, I) < 0 return N, otherwise return -N.
3020 resultArray = new TConstantUnion[maxObjectSize];
3021 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3022 for (size_t i = 0; i < maxObjectSize; i++)
3023 {
3024 if (dotProduct < 0)
3025 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3026 else
3027 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3028 }
3029 break;
3030 }
3031
3032 case EOpRefract:
3033 {
3034 ASSERT(basicType == EbtFloat);
3035 // genType refract(genType I, genType N, float eta) :
3036 // For the incident vector I and surface normal N, and the ratio of indices of
3037 // refraction eta,
3038 // return the refraction vector. The result is computed by
3039 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3040 // if (k < 0.0)
3041 // return genType(0.0)
3042 // else
3043 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3044 resultArray = new TConstantUnion[maxObjectSize];
3045 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3046 for (size_t i = 0; i < maxObjectSize; i++)
3047 {
3048 float eta = unionArrays[2][i].getFConst();
3049 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3050 if (k < 0.0f)
3051 resultArray[i].setFConst(0.0f);
3052 else
3053 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3054 (eta * dotProduct + sqrtf(k)) *
3055 unionArrays[1][i].getFConst());
3056 }
3057 break;
3058 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003059 case EOpBitfieldExtract:
3060 {
3061 resultArray = new TConstantUnion[maxObjectSize];
3062 for (size_t i = 0; i < maxObjectSize; ++i)
3063 {
3064 int offset = unionArrays[1][0].getIConst();
3065 int bits = unionArrays[2][0].getIConst();
3066 if (bits == 0)
3067 {
3068 if (aggregate->getBasicType() == EbtInt)
3069 {
3070 resultArray[i].setIConst(0);
3071 }
3072 else
3073 {
3074 ASSERT(aggregate->getBasicType() == EbtUInt);
3075 resultArray[i].setUConst(0);
3076 }
3077 }
3078 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3079 {
3080 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3081 &resultArray[i]);
3082 }
3083 else
3084 {
3085 // bits can be 32 here, so we need to avoid bit shift overflow.
3086 uint32_t maskMsb = 1u << (bits - 1);
3087 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3088 if (aggregate->getBasicType() == EbtInt)
3089 {
3090 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3091 uint32_t resultUnsigned = (value & mask) >> offset;
3092 if ((resultUnsigned & maskMsb) != 0)
3093 {
3094 // The most significant bits (from bits+1 to the most significant bit)
3095 // should be set to 1.
3096 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3097 resultUnsigned |= higherBitsMask;
3098 }
3099 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3100 }
3101 else
3102 {
3103 ASSERT(aggregate->getBasicType() == EbtUInt);
3104 uint32_t value = unionArrays[0][i].getUConst();
3105 resultArray[i].setUConst((value & mask) >> offset);
3106 }
3107 }
3108 }
3109 break;
3110 }
3111 case EOpBitfieldInsert:
3112 {
3113 resultArray = new TConstantUnion[maxObjectSize];
3114 for (size_t i = 0; i < maxObjectSize; ++i)
3115 {
3116 int offset = unionArrays[2][0].getIConst();
3117 int bits = unionArrays[3][0].getIConst();
3118 if (bits == 0)
3119 {
3120 if (aggregate->getBasicType() == EbtInt)
3121 {
3122 int32_t base = unionArrays[0][i].getIConst();
3123 resultArray[i].setIConst(base);
3124 }
3125 else
3126 {
3127 ASSERT(aggregate->getBasicType() == EbtUInt);
3128 uint32_t base = unionArrays[0][i].getUConst();
3129 resultArray[i].setUConst(base);
3130 }
3131 }
3132 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3133 {
3134 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3135 &resultArray[i]);
3136 }
3137 else
3138 {
3139 // bits can be 32 here, so we need to avoid bit shift overflow.
3140 uint32_t maskMsb = 1u << (bits - 1);
3141 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3142 uint32_t baseMask = ~insertMask;
3143 if (aggregate->getBasicType() == EbtInt)
3144 {
3145 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3146 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3147 uint32_t resultUnsigned =
3148 (base & baseMask) | ((insert << offset) & insertMask);
3149 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3150 }
3151 else
3152 {
3153 ASSERT(aggregate->getBasicType() == EbtUInt);
3154 uint32_t base = unionArrays[0][i].getUConst();
3155 uint32_t insert = unionArrays[1][i].getUConst();
3156 resultArray[i].setUConst((base & baseMask) |
3157 ((insert << offset) & insertMask));
3158 }
3159 }
3160 }
3161 break;
3162 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003163
3164 default:
3165 UNREACHABLE();
3166 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303167 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003168 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303169}
3170
3171// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04003172TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
3173{
3174 if (hashFunction == NULL || name.empty())
3175 return name;
3176 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
3177 TStringStream stream;
3178 stream << HASHED_NAME_PREFIX << std::hex << number;
3179 TString hashedName = stream.str();
3180 return hashedName;
3181}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003182
3183void TIntermTraverser::updateTree()
3184{
Olli Etuahoa6f22092015-05-08 18:31:10 +03003185 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
3186 {
3187 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
3188 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003189 if (!insertion.insertionsAfter.empty())
3190 {
3191 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
3192 insertion.insertionsAfter);
3193 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003194 }
3195 if (!insertion.insertionsBefore.empty())
3196 {
3197 bool inserted =
3198 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
3199 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003200 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03003201 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003202 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
3203 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003204 const NodeUpdateEntry &replacement = mReplacements[ii];
3205 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003206 bool replaced =
3207 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003208 ASSERT(replaced);
3209
Olli Etuahocd94ef92015-04-16 19:18:10 +03003210 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003211 {
3212 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03003213 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003214 // be replaced, we need to make sure we don't update the replaced
3215 // node; instead, we update the replacement node.
3216 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
3217 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003218 NodeUpdateEntry &replacement2 = mReplacements[jj];
3219 if (replacement2.parent == replacement.original)
3220 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003221 }
3222 }
3223 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003224 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
3225 {
3226 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
3227 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003228 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
3229 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003230 ASSERT(replaced);
3231 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03003232
Jamie Madill03d863c2016-07-27 18:15:53 -04003233 clearReplacementQueue();
3234}
3235
3236void TIntermTraverser::clearReplacementQueue()
3237{
Olli Etuahod4f303e2015-05-20 17:09:06 +03003238 mReplacements.clear();
3239 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04003240 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003241}
Jamie Madill1048e432016-07-23 18:51:28 -04003242
Jamie Madill03d863c2016-07-27 18:15:53 -04003243void TIntermTraverser::queueReplacement(TIntermNode *original,
3244 TIntermNode *replacement,
3245 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003246{
Jamie Madill03d863c2016-07-27 18:15:53 -04003247 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04003248}
3249
Jamie Madill03d863c2016-07-27 18:15:53 -04003250void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
3251 TIntermNode *original,
3252 TIntermNode *replacement,
3253 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003254{
Jamie Madill03d863c2016-07-27 18:15:53 -04003255 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
3256 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04003257}
Jamie Madill45bcc782016-11-07 13:58:48 -05003258
3259} // namespace sh