blob: 6bf2aa8857ffd229509b70594d1c3269d1539913 [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 Etuahob1edc4f2015-11-02 17:20:03 +0200275bool TIntermAggregate::areChildrenConstQualified()
276{
277 for (TIntermNode *&child : mSequence)
278 {
279 TIntermTyped *typed = child->getAsTyped();
280 if (typed && typed->getQualifier() != EvqConst)
281 {
282 return false;
283 }
284 }
285 return true;
286}
287
Olli Etuahod2a67b92014-10-21 16:42:57 +0300288void TIntermAggregate::setPrecisionFromChildren()
289{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300290 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300291 if (getBasicType() == EbtBool)
292 {
293 mType.setPrecision(EbpUndefined);
294 return;
295 }
296
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500297 TPrecision precision = EbpUndefined;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300298 TIntermSequence::iterator childIter = mSequence.begin();
299 while (childIter != mSequence.end())
300 {
301 TIntermTyped *typed = (*childIter)->getAsTyped();
302 if (typed)
303 precision = GetHigherPrecision(typed->getPrecision(), precision);
304 ++childIter;
305 }
306 mType.setPrecision(precision);
307}
308
Olli Etuaho9250cb22017-01-21 10:51:27 +0000309void TIntermAggregate::setPrecisionForBuiltInOp()
310{
311 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800312 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000313 if (!setPrecisionForSpecialBuiltInOp())
314 {
315 setPrecisionFromChildren();
316 }
317}
318
319bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
320{
321 switch (mOp)
322 {
323 case EOpBitfieldExtract:
324 mType.setPrecision(mSequence[0]->getAsTyped()->getPrecision());
325 return true;
326 case EOpBitfieldInsert:
327 mType.setPrecision(GetHigherPrecision(mSequence[0]->getAsTyped()->getPrecision(),
328 mSequence[1]->getAsTyped()->getPrecision()));
329 return true;
330 case EOpUaddCarry:
331 case EOpUsubBorrow:
332 mType.setPrecision(EbpHigh);
333 return true;
334 default:
335 return false;
336 }
337}
338
Olli Etuahod2a67b92014-10-21 16:42:57 +0300339void TIntermAggregate::setBuiltInFunctionPrecision()
340{
341 // All built-ins returning bool should be handled as ops, not functions.
342 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800343 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300344
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500345 TPrecision precision = EbpUndefined;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300346 TIntermSequence::iterator childIter = mSequence.begin();
347 while (childIter != mSequence.end())
348 {
349 TIntermTyped *typed = (*childIter)->getAsTyped();
350 // ESSL spec section 8: texture functions get their precision from the sampler.
351 if (typed && IsSampler(typed->getBasicType()))
352 {
353 precision = typed->getPrecision();
354 break;
355 }
356 ++childIter;
357 }
358 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
359 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100360 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300361 mType.setPrecision(EbpHigh);
362 else
363 mType.setPrecision(precision);
364}
365
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100366void TIntermBlock::appendStatement(TIntermNode *statement)
367{
Olli Etuaho13389b62016-10-16 11:48:18 +0100368 // Declaration nodes with no children can appear if all the declarators just added constants to
369 // the symbol table instead of generating code. They're no-ops so they aren't added to blocks.
370 if (statement != nullptr && (statement->getAsDeclarationNode() == nullptr ||
371 !statement->getAsDeclarationNode()->getSequence()->empty()))
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100372 {
373 mStatements.push_back(statement);
374 }
375}
376
Olli Etuaho16c745a2017-01-16 17:02:27 +0000377void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
378{
379 ASSERT(parameter != nullptr);
380 mParameters.push_back(parameter);
381}
382
Olli Etuaho13389b62016-10-16 11:48:18 +0100383void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
384{
385 ASSERT(declarator != nullptr);
386 ASSERT(declarator->getAsSymbolNode() != nullptr ||
387 (declarator->getAsBinaryNode() != nullptr &&
388 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
389 ASSERT(mDeclarators.empty() ||
390 declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType()));
391 mDeclarators.push_back(declarator);
392}
393
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300394bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
395{
396 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
397 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
398 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
399 return false;
400}
401
Olli Etuaho57961272016-09-14 13:57:46 +0300402bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400403{
404 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100405 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
406 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400407 return false;
408}
409
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500410bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200411{
412 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100413 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200414 return false;
415}
416
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500417bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200418{
419 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
420 return false;
421}
422
Olli Etuahod7a25242015-08-18 13:49:45 +0300423TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
424{
425 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
426 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
427 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
428 mLine = node.mLine;
429}
430
Olli Etuahod4f4c112016-04-15 15:11:24 +0300431bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
432{
433 TIntermAggregate *constructor = getAsAggregate();
434 if (!constructor || !constructor->isConstructor())
435 {
436 return false;
437 }
438 for (TIntermNode *&node : *constructor->getSequence())
439 {
440 if (!node->getAsConstantUnion())
441 return false;
442 }
443 return true;
444}
445
Corentin Wallez509e4562016-08-25 14:55:44 -0400446// static
447TIntermTyped *TIntermTyped::CreateIndexNode(int index)
448{
449 TConstantUnion *u = new TConstantUnion[1];
450 u[0].setIConst(index);
451
452 TType type(EbtInt, EbpUndefined, EvqConst, 1);
453 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
454 return node;
455}
456
457// static
458TIntermTyped *TIntermTyped::CreateZero(const TType &type)
459{
460 TType constType(type);
461 constType.setQualifier(EvqConst);
462
463 if (!type.isArray() && type.getBasicType() != EbtStruct)
464 {
465 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
466
467 size_t size = constType.getObjectSize();
468 TConstantUnion *u = new TConstantUnion[size];
469 for (size_t i = 0; i < size; ++i)
470 {
471 switch (type.getBasicType())
472 {
473 case EbtFloat:
474 u[i].setFConst(0.0f);
475 break;
476 case EbtInt:
477 u[i].setIConst(0);
478 break;
479 case EbtUInt:
480 u[i].setUConst(0u);
481 break;
482 case EbtBool:
483 u[i].setBConst(false);
484 break;
485 default:
Corentin Wallez17a5c062017-01-22 15:20:53 -0500486 // CreateZero is called by ParseContext that keeps parsing even when an error
487 // occurs, so it is possible for CreateZero to be called with non-basic types.
488 // This happens only on error condition but CreateZero needs to return a value
489 // with the correct type to continue the typecheck. That's why we handle
490 // non-basic type by setting whatever value, we just need the type to be right.
491 u[i].setIConst(42);
492 break;
Corentin Wallez509e4562016-08-25 14:55:44 -0400493 }
494 }
495
496 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
497 return node;
498 }
499
500 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
501 constructor->setType(constType);
502
503 if (type.isArray())
504 {
505 TType elementType(type);
506 elementType.clearArrayness();
507
508 size_t arraySize = type.getArraySize();
509 for (size_t i = 0; i < arraySize; ++i)
510 {
511 constructor->getSequence()->push_back(CreateZero(elementType));
512 }
513 }
514 else
515 {
516 ASSERT(type.getBasicType() == EbtStruct);
517
518 TStructure *structure = type.getStruct();
519 for (const auto &field : structure->fields())
520 {
521 constructor->getSequence()->push_back(CreateZero(*field->type()));
522 }
523 }
524
525 return constructor;
526}
527
Corentin Wallez36fd1002016-12-08 11:30:44 -0500528// static
529TIntermTyped *TIntermTyped::CreateBool(bool value)
530{
531 TConstantUnion *u = new TConstantUnion[1];
532 u[0].setBConst(value);
533
534 TType type(EbtBool, EbpUndefined, EvqConst, 1);
535 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
536 return node;
537}
538
Olli Etuahod7a25242015-08-18 13:49:45 +0300539TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
540{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200541 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300542}
543
Olli Etuahobd674552016-10-06 13:28:42 +0100544void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
545{
546 setName(function.getMangledName());
547 setId(function.getUniqueId());
548}
549
Olli Etuahod7a25242015-08-18 13:49:45 +0300550TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
551 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300552 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100553 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
554 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300555{
556 for (TIntermNode *child : node.mSequence)
557 {
558 TIntermTyped *typedChild = child->getAsTyped();
559 ASSERT(typedChild != nullptr);
560 TIntermTyped *childCopy = typedChild->deepCopy();
561 mSequence.push_back(childCopy);
562 }
563}
564
Olli Etuahob6fa0432016-09-28 16:28:05 +0100565TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
566{
567 TIntermTyped *operandCopy = node.mOperand->deepCopy();
568 ASSERT(operandCopy != nullptr);
569 mOperand = operandCopy;
570}
571
Olli Etuahod7a25242015-08-18 13:49:45 +0300572TIntermBinary::TIntermBinary(const TIntermBinary &node)
573 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
574{
575 TIntermTyped *leftCopy = node.mLeft->deepCopy();
576 TIntermTyped *rightCopy = node.mRight->deepCopy();
577 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
578 mLeft = leftCopy;
579 mRight = rightCopy;
580}
581
582TIntermUnary::TIntermUnary(const TIntermUnary &node)
583 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
584{
585 TIntermTyped *operandCopy = node.mOperand->deepCopy();
586 ASSERT(operandCopy != nullptr);
587 mOperand = operandCopy;
588}
589
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300590TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300591{
Olli Etuahod7a25242015-08-18 13:49:45 +0300592 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300593 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
594 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300595 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300596 mCondition = conditionCopy;
597 mTrueExpression = trueCopy;
598 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300599}
600
Jamie Madillb1a85f42014-08-19 15:23:24 -0400601bool TIntermOperator::isAssignment() const
602{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300603 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400604}
605
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300606bool TIntermOperator::isMultiplication() const
607{
608 switch (mOp)
609 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500610 case EOpMul:
611 case EOpMatrixTimesMatrix:
612 case EOpMatrixTimesVector:
613 case EOpMatrixTimesScalar:
614 case EOpVectorTimesMatrix:
615 case EOpVectorTimesScalar:
616 return true;
617 default:
618 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300619 }
620}
621
Jamie Madillb1a85f42014-08-19 15:23:24 -0400622//
623// returns true if the operator is for one of the constructors
624//
625bool TIntermOperator::isConstructor() const
626{
627 switch (mOp)
628 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500629 case EOpConstructVec2:
630 case EOpConstructVec3:
631 case EOpConstructVec4:
632 case EOpConstructMat2:
633 case EOpConstructMat2x3:
634 case EOpConstructMat2x4:
635 case EOpConstructMat3x2:
636 case EOpConstructMat3:
637 case EOpConstructMat3x4:
638 case EOpConstructMat4x2:
639 case EOpConstructMat4x3:
640 case EOpConstructMat4:
641 case EOpConstructFloat:
642 case EOpConstructIVec2:
643 case EOpConstructIVec3:
644 case EOpConstructIVec4:
645 case EOpConstructInt:
646 case EOpConstructUVec2:
647 case EOpConstructUVec3:
648 case EOpConstructUVec4:
649 case EOpConstructUInt:
650 case EOpConstructBVec2:
651 case EOpConstructBVec3:
652 case EOpConstructBVec4:
653 case EOpConstructBool:
654 case EOpConstructStruct:
655 return true;
656 default:
657 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400658 }
659}
660
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800661bool TIntermOperator::isFunctionCall() const
662{
663 switch (mOp)
664 {
665 case EOpCallFunctionInAST:
666 case EOpCallBuiltInFunction:
667 case EOpCallInternalRawFunction:
668 return true;
669 default:
670 return false;
671 }
672}
673
Olli Etuaho1dded802016-08-18 18:13:13 +0300674TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
675{
676 if (left.isMatrix())
677 {
678 if (right.isMatrix())
679 {
680 return EOpMatrixTimesMatrix;
681 }
682 else
683 {
684 if (right.isVector())
685 {
686 return EOpMatrixTimesVector;
687 }
688 else
689 {
690 return EOpMatrixTimesScalar;
691 }
692 }
693 }
694 else
695 {
696 if (right.isMatrix())
697 {
698 if (left.isVector())
699 {
700 return EOpVectorTimesMatrix;
701 }
702 else
703 {
704 return EOpMatrixTimesScalar;
705 }
706 }
707 else
708 {
709 // Neither operand is a matrix.
710 if (left.isVector() == right.isVector())
711 {
712 // Leave as component product.
713 return EOpMul;
714 }
715 else
716 {
717 return EOpVectorTimesScalar;
718 }
719 }
720 }
721}
722
723TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
724{
725 if (left.isMatrix())
726 {
727 if (right.isMatrix())
728 {
729 return EOpMatrixTimesMatrixAssign;
730 }
731 else
732 {
733 // right should be scalar, but this may not be validated yet.
734 return EOpMatrixTimesScalarAssign;
735 }
736 }
737 else
738 {
739 if (right.isMatrix())
740 {
741 // Left should be a vector, but this may not be validated yet.
742 return EOpVectorTimesMatrixAssign;
743 }
744 else
745 {
746 // Neither operand is a matrix.
747 if (left.isVector() == right.isVector())
748 {
749 // Leave as component product.
750 return EOpMulAssign;
751 }
752 else
753 {
754 // left should be vector and right should be scalar, but this may not be validated
755 // yet.
756 return EOpVectorTimesScalarAssign;
757 }
758 }
759 }
760}
761
Jamie Madillb1a85f42014-08-19 15:23:24 -0400762//
763// Make sure the type of a unary operator is appropriate for its
764// combination of operation and operand type.
765//
Olli Etuahoa2234302016-08-31 12:05:39 +0300766void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400767{
Olli Etuahoa2234302016-08-31 12:05:39 +0300768 TQualifier resultQualifier = EvqTemporary;
769 if (mOperand->getQualifier() == EvqConst)
770 resultQualifier = EvqConst;
771
772 unsigned char operandPrimarySize =
773 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400774 switch (mOp)
775 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300776 case EOpFloatBitsToInt:
777 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
778 break;
779 case EOpFloatBitsToUint:
780 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
781 break;
782 case EOpIntBitsToFloat:
783 case EOpUintBitsToFloat:
784 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
785 break;
786 case EOpPackSnorm2x16:
787 case EOpPackUnorm2x16:
788 case EOpPackHalf2x16:
789 setType(TType(EbtUInt, EbpHigh, resultQualifier));
790 break;
791 case EOpUnpackSnorm2x16:
792 case EOpUnpackUnorm2x16:
793 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
794 break;
795 case EOpUnpackHalf2x16:
796 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
797 break;
798 case EOpAny:
799 case EOpAll:
800 setType(TType(EbtBool, EbpUndefined, resultQualifier));
801 break;
802 case EOpLength:
803 case EOpDeterminant:
804 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
805 break;
806 case EOpTranspose:
807 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
808 static_cast<unsigned char>(mOperand->getType().getRows()),
809 static_cast<unsigned char>(mOperand->getType().getCols())));
810 break;
811 case EOpIsInf:
812 case EOpIsNan:
813 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
814 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000815 case EOpBitfieldReverse:
816 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
817 break;
818 case EOpBitCount:
819 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
820 break;
821 case EOpFindLSB:
822 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
823 break;
824 case EOpFindMSB:
825 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
826 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300827 default:
828 setType(mOperand->getType());
829 mType.setQualifier(resultQualifier);
830 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400831 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300832}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400833
Olli Etuahob6fa0432016-09-28 16:28:05 +0100834TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
835 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
836 mOperand(operand),
837 mSwizzleOffsets(swizzleOffsets)
838{
839 ASSERT(mSwizzleOffsets.size() <= 4);
840 promote();
841}
842
Olli Etuahoa2234302016-08-31 12:05:39 +0300843TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
844 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
845{
846 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400847}
848
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300849TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
850 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
851{
852 promote();
853}
854
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000855TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
856 : TIntermNode(), mSymbol(symbol)
857{
858 ASSERT(symbol);
859 setLine(line);
860}
861
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300862TIntermTernary::TIntermTernary(TIntermTyped *cond,
863 TIntermTyped *trueExpression,
864 TIntermTyped *falseExpression)
865 : TIntermTyped(trueExpression->getType()),
866 mCondition(cond),
867 mTrueExpression(trueExpression),
868 mFalseExpression(falseExpression)
869{
870 getTypePointer()->setQualifier(
871 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
872}
873
874// static
875TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
876 TIntermTyped *trueExpression,
877 TIntermTyped *falseExpression)
878{
879 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
880 falseExpression->getQualifier() == EvqConst)
881 {
882 return EvqConst;
883 }
884 return EvqTemporary;
885}
886
Olli Etuahob6fa0432016-09-28 16:28:05 +0100887void TIntermSwizzle::promote()
888{
889 TQualifier resultQualifier = EvqTemporary;
890 if (mOperand->getQualifier() == EvqConst)
891 resultQualifier = EvqConst;
892
893 auto numFields = mSwizzleOffsets.size();
894 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
895 static_cast<unsigned char>(numFields)));
896}
897
898bool TIntermSwizzle::hasDuplicateOffsets() const
899{
900 int offsetCount[4] = {0u, 0u, 0u, 0u};
901 for (const auto offset : mSwizzleOffsets)
902 {
903 offsetCount[offset]++;
904 if (offsetCount[offset] > 1)
905 {
906 return true;
907 }
908 }
909 return false;
910}
911
Olli Etuaho09b04a22016-12-15 13:30:26 +0000912bool TIntermSwizzle::offsetsMatch(int offset) const
913{
914 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
915}
916
Olli Etuahob6fa0432016-09-28 16:28:05 +0100917void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
918{
919 for (const int offset : mSwizzleOffsets)
920 {
921 switch (offset)
922 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500923 case 0:
924 *out << "x";
925 break;
926 case 1:
927 *out << "y";
928 break;
929 case 2:
930 *out << "z";
931 break;
932 case 3:
933 *out << "w";
934 break;
935 default:
936 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +0100937 }
938 }
939}
940
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100941TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
942 const TIntermTyped *left,
943 const TIntermTyped *right)
944{
945 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
946 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
947 right->getQualifier() != EvqConst)
948 {
949 return EvqTemporary;
950 }
951 return EvqConst;
952}
Olli Etuahob6fa0432016-09-28 16:28:05 +0100953
954// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300955void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400956{
Olli Etuaho1dded802016-08-18 18:13:13 +0300957 ASSERT(!isMultiplication() ||
958 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
959
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100960 // Comma is handled as a special case.
961 if (mOp == EOpComma)
962 {
963 setType(mRight->getType());
964 return;
965 }
966
Jamie Madillb1a85f42014-08-19 15:23:24 -0400967 // Base assumption: just make the type the same as the left
968 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400969 setType(mLeft->getType());
970
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200971 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400972 // Binary operations results in temporary variables unless both
973 // operands are const.
974 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
975 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200976 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400977 getTypePointer()->setQualifier(EvqTemporary);
978 }
979
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300980 // Handle indexing ops.
981 switch (mOp)
982 {
983 case EOpIndexDirect:
984 case EOpIndexIndirect:
985 if (mLeft->isArray())
986 {
987 mType.clearArrayness();
988 }
989 else if (mLeft->isMatrix())
990 {
991 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
992 static_cast<unsigned char>(mLeft->getRows())));
993 }
994 else if (mLeft->isVector())
995 {
996 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
997 }
998 else
999 {
1000 UNREACHABLE();
1001 }
1002 return;
1003 case EOpIndexDirectStruct:
1004 {
1005 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1006 const int i = mRight->getAsConstantUnion()->getIConst(0);
1007 setType(*fields[i]->type());
1008 getTypePointer()->setQualifier(resultQualifier);
1009 return;
1010 }
1011 case EOpIndexDirectInterfaceBlock:
1012 {
1013 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1014 const int i = mRight->getAsConstantUnion()->getIConst(0);
1015 setType(*fields[i]->type());
1016 getTypePointer()->setQualifier(resultQualifier);
1017 return;
1018 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001019 default:
1020 break;
1021 }
1022
1023 ASSERT(mLeft->isArray() == mRight->isArray());
1024
1025 // The result gets promoted to the highest precision.
1026 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1027 getTypePointer()->setPrecision(higherPrecision);
1028
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001029 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001030
1031 //
1032 // All scalars or structs. Code after this test assumes this case is removed!
1033 //
1034 if (nominalSize == 1)
1035 {
1036 switch (mOp)
1037 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001038 //
1039 // Promote to conditional
1040 //
1041 case EOpEqual:
1042 case EOpNotEqual:
1043 case EOpLessThan:
1044 case EOpGreaterThan:
1045 case EOpLessThanEqual:
1046 case EOpGreaterThanEqual:
1047 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1048 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001049
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001050 //
1051 // And and Or operate on conditionals
1052 //
1053 case EOpLogicalAnd:
1054 case EOpLogicalXor:
1055 case EOpLogicalOr:
1056 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1057 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1058 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001059
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001060 default:
1061 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001062 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001063 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001064 }
1065
1066 // If we reach here, at least one of the operands is vector or matrix.
1067 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001068 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001069
Jamie Madillb1a85f42014-08-19 15:23:24 -04001070 switch (mOp)
1071 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001072 case EOpMul:
1073 break;
1074 case EOpMatrixTimesScalar:
1075 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001076 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001077 setType(TType(basicType, higherPrecision, resultQualifier,
1078 static_cast<unsigned char>(mRight->getCols()),
1079 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001080 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001081 break;
1082 case EOpMatrixTimesVector:
1083 setType(TType(basicType, higherPrecision, resultQualifier,
1084 static_cast<unsigned char>(mLeft->getRows()), 1));
1085 break;
1086 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001087 setType(TType(basicType, higherPrecision, resultQualifier,
1088 static_cast<unsigned char>(mRight->getCols()),
1089 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001090 break;
1091 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001092 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001093 static_cast<unsigned char>(nominalSize), 1));
1094 break;
1095 case EOpVectorTimesMatrix:
1096 setType(TType(basicType, higherPrecision, resultQualifier,
1097 static_cast<unsigned char>(mRight->getCols()), 1));
1098 break;
1099 case EOpMulAssign:
1100 case EOpVectorTimesScalarAssign:
1101 case EOpVectorTimesMatrixAssign:
1102 case EOpMatrixTimesScalarAssign:
1103 case EOpMatrixTimesMatrixAssign:
1104 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1105 break;
1106 case EOpAssign:
1107 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001108 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1109 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1110 break;
1111 case EOpAdd:
1112 case EOpSub:
1113 case EOpDiv:
1114 case EOpIMod:
1115 case EOpBitShiftLeft:
1116 case EOpBitShiftRight:
1117 case EOpBitwiseAnd:
1118 case EOpBitwiseXor:
1119 case EOpBitwiseOr:
1120 case EOpAddAssign:
1121 case EOpSubAssign:
1122 case EOpDivAssign:
1123 case EOpIModAssign:
1124 case EOpBitShiftLeftAssign:
1125 case EOpBitShiftRightAssign:
1126 case EOpBitwiseAndAssign:
1127 case EOpBitwiseXorAssign:
1128 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001129 {
1130 const int secondarySize =
1131 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1132 setType(TType(basicType, higherPrecision, resultQualifier,
1133 static_cast<unsigned char>(nominalSize),
1134 static_cast<unsigned char>(secondarySize)));
1135 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001136 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001137 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001138 case EOpEqual:
1139 case EOpNotEqual:
1140 case EOpLessThan:
1141 case EOpGreaterThan:
1142 case EOpLessThanEqual:
1143 case EOpGreaterThanEqual:
1144 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1145 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001146 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001147 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001148
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001149 case EOpIndexDirect:
1150 case EOpIndexIndirect:
1151 case EOpIndexDirectInterfaceBlock:
1152 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001153 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001154 UNREACHABLE();
1155 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001156 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001157 UNREACHABLE();
1158 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001159 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001160}
1161
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001162const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001163{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001164 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001165 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001166 ASSERT(index < static_cast<int>(getType().getArraySize()));
1167 TType arrayElementType = getType();
1168 arrayElementType.clearArrayness();
1169 size_t arrayElementSize = arrayElementType.getObjectSize();
1170 return &mUnionArrayPointer[arrayElementSize * index];
1171 }
1172 else if (isMatrix())
1173 {
1174 ASSERT(index < getType().getCols());
1175 int size = getType().getRows();
1176 return &mUnionArrayPointer[size * index];
1177 }
1178 else if (isVector())
1179 {
1180 ASSERT(index < getType().getNominalSize());
1181 return &mUnionArrayPointer[index];
1182 }
1183 else
1184 {
1185 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001186 return nullptr;
1187 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001188}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001189
Olli Etuahob6fa0432016-09-28 16:28:05 +01001190TIntermTyped *TIntermSwizzle::fold()
1191{
1192 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1193 if (operandConstant == nullptr)
1194 {
1195 return nullptr;
1196 }
1197
1198 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1199 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1200 {
1201 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1202 }
1203 return CreateFoldedNode(constArray, this, mType.getQualifier());
1204}
1205
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001206TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1207{
1208 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1209 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1210 switch (mOp)
1211 {
1212 case EOpIndexDirect:
1213 {
1214 if (leftConstant == nullptr || rightConstant == nullptr)
1215 {
1216 return nullptr;
1217 }
1218 int index = rightConstant->getIConst(0);
1219
1220 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1221 return CreateFoldedNode(constArray, this, mType.getQualifier());
1222 }
1223 case EOpIndexDirectStruct:
1224 {
1225 if (leftConstant == nullptr || rightConstant == nullptr)
1226 {
1227 return nullptr;
1228 }
1229 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1230 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1231
1232 size_t previousFieldsSize = 0;
1233 for (size_t i = 0; i < index; ++i)
1234 {
1235 previousFieldsSize += fields[i]->type()->getObjectSize();
1236 }
1237
1238 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1239 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1240 }
1241 case EOpIndexIndirect:
1242 case EOpIndexDirectInterfaceBlock:
1243 // Can never be constant folded.
1244 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001245 default:
1246 {
1247 if (leftConstant == nullptr || rightConstant == nullptr)
1248 {
1249 return nullptr;
1250 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001251 TConstantUnion *constArray =
1252 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001253
1254 // Nodes may be constant folded without being qualified as constant.
1255 return CreateFoldedNode(constArray, this, mType.getQualifier());
1256 }
1257 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001258}
1259
Olli Etuahof119a262016-08-19 15:54:22 +03001260TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001261{
1262 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1263 if (operandConstant == nullptr)
1264 {
1265 return nullptr;
1266 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301267
1268 TConstantUnion *constArray = nullptr;
1269 switch (mOp)
1270 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001271 case EOpAny:
1272 case EOpAll:
1273 case EOpLength:
1274 case EOpTranspose:
1275 case EOpDeterminant:
1276 case EOpInverse:
1277 case EOpPackSnorm2x16:
1278 case EOpUnpackSnorm2x16:
1279 case EOpPackUnorm2x16:
1280 case EOpUnpackUnorm2x16:
1281 case EOpPackHalf2x16:
1282 case EOpUnpackHalf2x16:
1283 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1284 break;
1285 default:
1286 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1287 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301288 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001289
1290 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001291 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001292}
1293
Olli Etuahof119a262016-08-19 15:54:22 +03001294TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001295{
1296 // Make sure that all params are constant before actual constant folding.
1297 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001298 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001299 if (param->getAsConstantUnion() == nullptr)
1300 {
1301 return nullptr;
1302 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001303 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001304 TConstantUnion *constArray = nullptr;
1305 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001306 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001307 else
Olli Etuahof119a262016-08-19 15:54:22 +03001308 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001309
1310 // Nodes may be constant folded without being qualified as constant.
1311 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
1312 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +03001313}
1314
Jamie Madillb1a85f42014-08-19 15:23:24 -04001315//
1316// The fold functions see if an operation on a constant can be done in place,
1317// without generating run-time code.
1318//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001319// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001320//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001321TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1322 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001323 TDiagnostics *diagnostics,
1324 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001325{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001326 const TConstantUnion *leftArray = getUnionArrayPointer();
1327 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001328
Olli Etuahof119a262016-08-19 15:54:22 +03001329 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001330
1331 size_t objectSize = getType().getObjectSize();
1332
1333 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1334 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1335 {
1336 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1337 }
1338 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1339 {
1340 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001341 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001342 objectSize = rightNode->getType().getObjectSize();
1343 }
1344
1345 TConstantUnion *resultArray = nullptr;
1346
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001347 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001348 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001349 case EOpAdd:
1350 resultArray = new TConstantUnion[objectSize];
1351 for (size_t i = 0; i < objectSize; i++)
1352 resultArray[i] =
1353 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1354 break;
1355 case EOpSub:
1356 resultArray = new TConstantUnion[objectSize];
1357 for (size_t i = 0; i < objectSize; i++)
1358 resultArray[i] =
1359 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1360 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001361
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001362 case EOpMul:
1363 case EOpVectorTimesScalar:
1364 case EOpMatrixTimesScalar:
1365 resultArray = new TConstantUnion[objectSize];
1366 for (size_t i = 0; i < objectSize; i++)
1367 resultArray[i] =
1368 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1369 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001370
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001371 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001372 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001373 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001374 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001375
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001376 const int leftCols = getCols();
1377 const int leftRows = getRows();
1378 const int rightCols = rightNode->getType().getCols();
1379 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001380 const int resultCols = rightCols;
1381 const int resultRows = leftRows;
1382
1383 resultArray = new TConstantUnion[resultCols * resultRows];
1384 for (int row = 0; row < resultRows; row++)
1385 {
1386 for (int column = 0; column < resultCols; column++)
1387 {
1388 resultArray[resultRows * column + row].setFConst(0.0f);
1389 for (int i = 0; i < leftCols; i++)
1390 {
1391 resultArray[resultRows * column + row].setFConst(
1392 resultArray[resultRows * column + row].getFConst() +
1393 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001394 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001395 }
1396 }
1397 }
1398 }
1399 break;
1400
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001401 case EOpDiv:
1402 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001403 {
1404 resultArray = new TConstantUnion[objectSize];
1405 for (size_t i = 0; i < objectSize; i++)
1406 {
1407 switch (getType().getBasicType())
1408 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001409 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001410 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001411 ASSERT(op == EOpDiv);
1412 float dividend = leftArray[i].getFConst();
1413 float divisor = rightArray[i].getFConst();
1414 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001415 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001416 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001417 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001418 diagnostics->warning(
1419 getLine(),
1420 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001421 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001422 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001423 }
1424 else
1425 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001426 diagnostics->warning(getLine(),
1427 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001428 bool negativeResult =
1429 std::signbit(dividend) != std::signbit(divisor);
1430 resultArray[i].setFConst(
1431 negativeResult ? -std::numeric_limits<float>::infinity()
1432 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001433 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001434 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001435 else if (gl::isInf(dividend) && gl::isInf(divisor))
1436 {
1437 diagnostics->warning(getLine(),
1438 "Infinity divided by infinity during constant "
1439 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001440 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001441 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1442 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001443 else
1444 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001445 float result = dividend / divisor;
1446 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001447 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001448 diagnostics->warning(
1449 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001450 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001451 }
1452 resultArray[i].setFConst(result);
1453 }
1454 break;
1455 }
1456 case EbtInt:
1457 if (rightArray[i] == 0)
1458 {
1459 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001460 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001461 resultArray[i].setIConst(INT_MAX);
1462 }
1463 else
1464 {
1465 int lhs = leftArray[i].getIConst();
1466 int divisor = rightArray[i].getIConst();
1467 if (op == EOpDiv)
1468 {
1469 // Check for the special case where the minimum representable number
1470 // is
1471 // divided by -1. If left alone this leads to integer overflow in
1472 // C++.
1473 // ESSL 3.00.6 section 4.1.3 Integers:
1474 // "However, for the case where the minimum representable value is
1475 // divided by -1, it is allowed to return either the minimum
1476 // representable value or the maximum representable value."
1477 if (lhs == -0x7fffffff - 1 && divisor == -1)
1478 {
1479 resultArray[i].setIConst(0x7fffffff);
1480 }
1481 else
1482 {
1483 resultArray[i].setIConst(lhs / divisor);
1484 }
Olli Etuahod4453572016-09-27 13:21:46 +01001485 }
1486 else
1487 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001488 ASSERT(op == EOpIMod);
1489 if (lhs < 0 || divisor < 0)
1490 {
1491 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1492 // when
1493 // either one of the operands is negative.
1494 diagnostics->warning(getLine(),
1495 "Negative modulus operator operand "
1496 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001497 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001498 resultArray[i].setIConst(0);
1499 }
1500 else
1501 {
1502 resultArray[i].setIConst(lhs % divisor);
1503 }
Olli Etuahod4453572016-09-27 13:21:46 +01001504 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001505 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001506 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001507
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001508 case EbtUInt:
1509 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001510 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001511 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001512 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001513 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001514 }
1515 else
1516 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001517 if (op == EOpDiv)
1518 {
1519 resultArray[i].setUConst(leftArray[i].getUConst() /
1520 rightArray[i].getUConst());
1521 }
1522 else
1523 {
1524 ASSERT(op == EOpIMod);
1525 resultArray[i].setUConst(leftArray[i].getUConst() %
1526 rightArray[i].getUConst());
1527 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001528 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001529 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001530
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001531 default:
1532 UNREACHABLE();
1533 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001534 }
1535 }
1536 }
1537 break;
1538
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001539 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001540 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001541 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001542 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001543
1544 const int matrixCols = getCols();
1545 const int matrixRows = getRows();
1546
1547 resultArray = new TConstantUnion[matrixRows];
1548
1549 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1550 {
1551 resultArray[matrixRow].setFConst(0.0f);
1552 for (int col = 0; col < matrixCols; col++)
1553 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001554 resultArray[matrixRow].setFConst(
1555 resultArray[matrixRow].getFConst() +
1556 leftArray[col * matrixRows + matrixRow].getFConst() *
1557 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001558 }
1559 }
1560 }
1561 break;
1562
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001563 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001564 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001565 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001566 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001567
1568 const int matrixCols = rightNode->getType().getCols();
1569 const int matrixRows = rightNode->getType().getRows();
1570
1571 resultArray = new TConstantUnion[matrixCols];
1572
1573 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1574 {
1575 resultArray[matrixCol].setFConst(0.0f);
1576 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1577 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001578 resultArray[matrixCol].setFConst(
1579 resultArray[matrixCol].getFConst() +
1580 leftArray[matrixRow].getFConst() *
1581 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001582 }
1583 }
1584 }
1585 break;
1586
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001587 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001588 {
1589 resultArray = new TConstantUnion[objectSize];
1590 for (size_t i = 0; i < objectSize; i++)
1591 {
1592 resultArray[i] = leftArray[i] && rightArray[i];
1593 }
1594 }
1595 break;
1596
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001597 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001598 {
1599 resultArray = new TConstantUnion[objectSize];
1600 for (size_t i = 0; i < objectSize; i++)
1601 {
1602 resultArray[i] = leftArray[i] || rightArray[i];
1603 }
1604 }
1605 break;
1606
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001607 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001608 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001609 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001610 resultArray = new TConstantUnion[objectSize];
1611 for (size_t i = 0; i < objectSize; i++)
1612 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001613 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001614 }
1615 }
1616 break;
1617
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 case EOpBitwiseAnd:
1619 resultArray = new TConstantUnion[objectSize];
1620 for (size_t i = 0; i < objectSize; i++)
1621 resultArray[i] = leftArray[i] & rightArray[i];
1622 break;
1623 case EOpBitwiseXor:
1624 resultArray = new TConstantUnion[objectSize];
1625 for (size_t i = 0; i < objectSize; i++)
1626 resultArray[i] = leftArray[i] ^ rightArray[i];
1627 break;
1628 case EOpBitwiseOr:
1629 resultArray = new TConstantUnion[objectSize];
1630 for (size_t i = 0; i < objectSize; i++)
1631 resultArray[i] = leftArray[i] | rightArray[i];
1632 break;
1633 case EOpBitShiftLeft:
1634 resultArray = new TConstantUnion[objectSize];
1635 for (size_t i = 0; i < objectSize; i++)
1636 resultArray[i] =
1637 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1638 break;
1639 case EOpBitShiftRight:
1640 resultArray = new TConstantUnion[objectSize];
1641 for (size_t i = 0; i < objectSize; i++)
1642 resultArray[i] =
1643 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1644 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001645
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001646 case EOpLessThan:
1647 ASSERT(objectSize == 1);
1648 resultArray = new TConstantUnion[1];
1649 resultArray->setBConst(*leftArray < *rightArray);
1650 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001651
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001652 case EOpGreaterThan:
1653 ASSERT(objectSize == 1);
1654 resultArray = new TConstantUnion[1];
1655 resultArray->setBConst(*leftArray > *rightArray);
1656 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001657
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001658 case EOpLessThanEqual:
1659 ASSERT(objectSize == 1);
1660 resultArray = new TConstantUnion[1];
1661 resultArray->setBConst(!(*leftArray > *rightArray));
1662 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001663
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001664 case EOpGreaterThanEqual:
1665 ASSERT(objectSize == 1);
1666 resultArray = new TConstantUnion[1];
1667 resultArray->setBConst(!(*leftArray < *rightArray));
1668 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001669
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001670 case EOpEqual:
1671 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001672 {
1673 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001674 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001675 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001676 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001677 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001678 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001679 equal = false;
1680 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001681 }
1682 }
1683 if (op == EOpEqual)
1684 {
1685 resultArray->setBConst(equal);
1686 }
1687 else
1688 {
1689 resultArray->setBConst(!equal);
1690 }
1691 }
1692 break;
1693
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001694 default:
1695 UNREACHABLE();
1696 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001697 }
1698 return resultArray;
1699}
1700
Olli Etuahof119a262016-08-19 15:54:22 +03001701// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1702// code. Returns the constant value to keep using. Nullptr should not be returned.
1703TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001704{
Olli Etuahof119a262016-08-19 15:54:22 +03001705 // Do operations where the return type may have a different number of components compared to the
1706 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001707
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001708 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001709 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301710
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001711 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301712 TConstantUnion *resultArray = nullptr;
1713 switch (op)
1714 {
Olli Etuahof119a262016-08-19 15:54:22 +03001715 case EOpAny:
1716 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301717 resultArray = new TConstantUnion();
1718 resultArray->setBConst(false);
1719 for (size_t i = 0; i < objectSize; i++)
1720 {
1721 if (operandArray[i].getBConst())
1722 {
1723 resultArray->setBConst(true);
1724 break;
1725 }
1726 }
1727 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301728
Olli Etuahof119a262016-08-19 15:54:22 +03001729 case EOpAll:
1730 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301731 resultArray = new TConstantUnion();
1732 resultArray->setBConst(true);
1733 for (size_t i = 0; i < objectSize; i++)
1734 {
1735 if (!operandArray[i].getBConst())
1736 {
1737 resultArray->setBConst(false);
1738 break;
1739 }
1740 }
1741 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301742
Olli Etuahof119a262016-08-19 15:54:22 +03001743 case EOpLength:
1744 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301745 resultArray = new TConstantUnion();
1746 resultArray->setFConst(VectorLength(operandArray, objectSize));
1747 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301748
Olli Etuahof119a262016-08-19 15:54:22 +03001749 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301750 {
Olli Etuahof119a262016-08-19 15:54:22 +03001751 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301752 resultArray = new TConstantUnion[objectSize];
1753 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001754 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301755 SetUnionArrayFromMatrix(result, resultArray);
1756 break;
1757 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301758
Olli Etuahof119a262016-08-19 15:54:22 +03001759 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301760 {
Olli Etuahof119a262016-08-19 15:54:22 +03001761 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301762 unsigned int size = getType().getNominalSize();
1763 ASSERT(size >= 2 && size <= 4);
1764 resultArray = new TConstantUnion();
1765 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1766 break;
1767 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301768
Olli Etuahof119a262016-08-19 15:54:22 +03001769 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301770 {
Olli Etuahof119a262016-08-19 15:54:22 +03001771 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301772 unsigned int size = getType().getNominalSize();
1773 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001774 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301775 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1776 SetUnionArrayFromMatrix(result, resultArray);
1777 break;
1778 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301779
Olli Etuahof119a262016-08-19 15:54:22 +03001780 case EOpPackSnorm2x16:
1781 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301782 ASSERT(getType().getNominalSize() == 2);
1783 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001784 resultArray->setUConst(
1785 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301786 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301787
Olli Etuahof119a262016-08-19 15:54:22 +03001788 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301789 {
Olli Etuahof119a262016-08-19 15:54:22 +03001790 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301791 resultArray = new TConstantUnion[2];
1792 float f1, f2;
1793 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1794 resultArray[0].setFConst(f1);
1795 resultArray[1].setFConst(f2);
1796 break;
1797 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301798
Olli Etuahof119a262016-08-19 15:54:22 +03001799 case EOpPackUnorm2x16:
1800 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301801 ASSERT(getType().getNominalSize() == 2);
1802 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001803 resultArray->setUConst(
1804 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301805 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301806
Olli Etuahof119a262016-08-19 15:54:22 +03001807 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301808 {
Olli Etuahof119a262016-08-19 15:54:22 +03001809 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301810 resultArray = new TConstantUnion[2];
1811 float f1, f2;
1812 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1813 resultArray[0].setFConst(f1);
1814 resultArray[1].setFConst(f2);
1815 break;
1816 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301817
Olli Etuahof119a262016-08-19 15:54:22 +03001818 case EOpPackHalf2x16:
1819 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301820 ASSERT(getType().getNominalSize() == 2);
1821 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001822 resultArray->setUConst(
1823 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301824 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301825
Olli Etuahof119a262016-08-19 15:54:22 +03001826 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301827 {
Olli Etuahof119a262016-08-19 15:54:22 +03001828 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301829 resultArray = new TConstantUnion[2];
1830 float f1, f2;
1831 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1832 resultArray[0].setFConst(f1);
1833 resultArray[1].setFConst(f2);
1834 break;
1835 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301836
Olli Etuahof119a262016-08-19 15:54:22 +03001837 default:
1838 UNREACHABLE();
1839 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301840 }
1841
1842 return resultArray;
1843}
1844
Olli Etuahof119a262016-08-19 15:54:22 +03001845TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1846 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301847{
Olli Etuahof119a262016-08-19 15:54:22 +03001848 // Do unary operations where each component of the result is computed based on the corresponding
1849 // component of the operand. Also folds normalize, though the divisor in that case takes all
1850 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301851
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001852 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001853 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001854
1855 size_t objectSize = getType().getObjectSize();
1856
Arun Patoleab2b9a22015-07-06 18:27:56 +05301857 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1858 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301859 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001860 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301861 {
Olli Etuahof119a262016-08-19 15:54:22 +03001862 case EOpNegative:
1863 switch (getType().getBasicType())
1864 {
1865 case EbtFloat:
1866 resultArray[i].setFConst(-operandArray[i].getFConst());
1867 break;
1868 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001869 if (operandArray[i] == std::numeric_limits<int>::min())
1870 {
1871 // The minimum representable integer doesn't have a positive
1872 // counterpart, rather the negation overflows and in ESSL is supposed to
1873 // wrap back to the minimum representable integer. Make sure that we
1874 // don't actually let the negation overflow, which has undefined
1875 // behavior in C++.
1876 resultArray[i].setIConst(std::numeric_limits<int>::min());
1877 }
1878 else
1879 {
1880 resultArray[i].setIConst(-operandArray[i].getIConst());
1881 }
Olli Etuahof119a262016-08-19 15:54:22 +03001882 break;
1883 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001884 if (operandArray[i] == 0x80000000u)
1885 {
1886 resultArray[i].setUConst(0x80000000u);
1887 }
1888 else
1889 {
1890 resultArray[i].setUConst(static_cast<unsigned int>(
1891 -static_cast<int>(operandArray[i].getUConst())));
1892 }
Olli Etuahof119a262016-08-19 15:54:22 +03001893 break;
1894 default:
1895 UNREACHABLE();
1896 return nullptr;
1897 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301898 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301899
Olli Etuahof119a262016-08-19 15:54:22 +03001900 case EOpPositive:
1901 switch (getType().getBasicType())
1902 {
1903 case EbtFloat:
1904 resultArray[i].setFConst(operandArray[i].getFConst());
1905 break;
1906 case EbtInt:
1907 resultArray[i].setIConst(operandArray[i].getIConst());
1908 break;
1909 case EbtUInt:
1910 resultArray[i].setUConst(static_cast<unsigned int>(
1911 static_cast<int>(operandArray[i].getUConst())));
1912 break;
1913 default:
1914 UNREACHABLE();
1915 return nullptr;
1916 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301917 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301918
Olli Etuahof119a262016-08-19 15:54:22 +03001919 case EOpLogicalNot:
1920 switch (getType().getBasicType())
1921 {
1922 case EbtBool:
1923 resultArray[i].setBConst(!operandArray[i].getBConst());
1924 break;
1925 default:
1926 UNREACHABLE();
1927 return nullptr;
1928 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301929 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301930
Olli Etuahof119a262016-08-19 15:54:22 +03001931 case EOpBitwiseNot:
1932 switch (getType().getBasicType())
1933 {
1934 case EbtInt:
1935 resultArray[i].setIConst(~operandArray[i].getIConst());
1936 break;
1937 case EbtUInt:
1938 resultArray[i].setUConst(~operandArray[i].getUConst());
1939 break;
1940 default:
1941 UNREACHABLE();
1942 return nullptr;
1943 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301944 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945
Olli Etuahof119a262016-08-19 15:54:22 +03001946 case EOpRadians:
1947 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301948 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1949 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301950
Olli Etuahof119a262016-08-19 15:54:22 +03001951 case EOpDegrees:
1952 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301953 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1954 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301955
Olli Etuahof119a262016-08-19 15:54:22 +03001956 case EOpSin:
1957 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301958 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301959
Olli Etuahof119a262016-08-19 15:54:22 +03001960 case EOpCos:
1961 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1962 break;
1963
1964 case EOpTan:
1965 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1966 break;
1967
1968 case EOpAsin:
1969 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1970 // 0.
1971 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1972 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1973 diagnostics, &resultArray[i]);
1974 else
1975 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1976 break;
1977
1978 case EOpAcos:
1979 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1980 // 0.
1981 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1982 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1983 diagnostics, &resultArray[i]);
1984 else
1985 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1986 break;
1987
1988 case EOpAtan:
1989 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1990 break;
1991
1992 case EOpSinh:
1993 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1994 break;
1995
1996 case EOpCosh:
1997 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1998 break;
1999
2000 case EOpTanh:
2001 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2002 break;
2003
2004 case EOpAsinh:
2005 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2006 break;
2007
2008 case EOpAcosh:
2009 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2010 if (operandArray[i].getFConst() < 1.0f)
2011 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2012 diagnostics, &resultArray[i]);
2013 else
2014 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2015 break;
2016
2017 case EOpAtanh:
2018 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2019 // 0.
2020 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2021 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2022 diagnostics, &resultArray[i]);
2023 else
2024 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2025 break;
2026
2027 case EOpAbs:
2028 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302029 {
Olli Etuahof119a262016-08-19 15:54:22 +03002030 case EbtFloat:
2031 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2032 break;
2033 case EbtInt:
2034 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2035 break;
2036 default:
2037 UNREACHABLE();
2038 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302039 }
2040 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002041
2042 case EOpSign:
2043 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302044 {
Olli Etuahof119a262016-08-19 15:54:22 +03002045 case EbtFloat:
2046 {
2047 float fConst = operandArray[i].getFConst();
2048 float fResult = 0.0f;
2049 if (fConst > 0.0f)
2050 fResult = 1.0f;
2051 else if (fConst < 0.0f)
2052 fResult = -1.0f;
2053 resultArray[i].setFConst(fResult);
2054 break;
2055 }
2056 case EbtInt:
2057 {
2058 int iConst = operandArray[i].getIConst();
2059 int iResult = 0;
2060 if (iConst > 0)
2061 iResult = 1;
2062 else if (iConst < 0)
2063 iResult = -1;
2064 resultArray[i].setIConst(iResult);
2065 break;
2066 }
2067 default:
2068 UNREACHABLE();
2069 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302070 }
2071 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302072
Olli Etuahof119a262016-08-19 15:54:22 +03002073 case EOpFloor:
2074 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2075 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302076
Olli Etuahof119a262016-08-19 15:54:22 +03002077 case EOpTrunc:
2078 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2079 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302080
Olli Etuahof119a262016-08-19 15:54:22 +03002081 case EOpRound:
2082 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2083 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302084
Olli Etuahof119a262016-08-19 15:54:22 +03002085 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302086 {
Olli Etuahof119a262016-08-19 15:54:22 +03002087 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302088 float x = operandArray[i].getFConst();
2089 float result;
2090 float fractPart = modff(x, &result);
2091 if (fabsf(fractPart) == 0.5f)
2092 result = 2.0f * roundf(x / 2.0f);
2093 else
2094 result = roundf(x);
2095 resultArray[i].setFConst(result);
2096 break;
2097 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302098
Olli Etuahof119a262016-08-19 15:54:22 +03002099 case EOpCeil:
2100 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2101 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302102
Olli Etuahof119a262016-08-19 15:54:22 +03002103 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302104 {
Olli Etuahof119a262016-08-19 15:54:22 +03002105 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302106 float x = operandArray[i].getFConst();
2107 resultArray[i].setFConst(x - floorf(x));
2108 break;
2109 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302110
Olli Etuahof119a262016-08-19 15:54:22 +03002111 case EOpIsNan:
2112 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302113 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2114 break;
Arun Patole551279e2015-07-07 18:18:23 +05302115
Olli Etuahof119a262016-08-19 15:54:22 +03002116 case EOpIsInf:
2117 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302118 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2119 break;
Arun Patole551279e2015-07-07 18:18:23 +05302120
Olli Etuahof119a262016-08-19 15:54:22 +03002121 case EOpFloatBitsToInt:
2122 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302123 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2124 break;
Arun Patole551279e2015-07-07 18:18:23 +05302125
Olli Etuahof119a262016-08-19 15:54:22 +03002126 case EOpFloatBitsToUint:
2127 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302128 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2129 break;
Arun Patole551279e2015-07-07 18:18:23 +05302130
Olli Etuahof119a262016-08-19 15:54:22 +03002131 case EOpIntBitsToFloat:
2132 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302133 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2134 break;
Arun Patole551279e2015-07-07 18:18:23 +05302135
Olli Etuahof119a262016-08-19 15:54:22 +03002136 case EOpUintBitsToFloat:
2137 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302138 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2139 break;
Arun Patole551279e2015-07-07 18:18:23 +05302140
Olli Etuahof119a262016-08-19 15:54:22 +03002141 case EOpExp:
2142 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2143 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302144
Olli Etuahof119a262016-08-19 15:54:22 +03002145 case EOpLog:
2146 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2147 if (operandArray[i].getFConst() <= 0.0f)
2148 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2149 diagnostics, &resultArray[i]);
2150 else
2151 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2152 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302153
Olli Etuahof119a262016-08-19 15:54:22 +03002154 case EOpExp2:
2155 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2156 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302157
Olli Etuahof119a262016-08-19 15:54:22 +03002158 case EOpLog2:
2159 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2160 // And log2f is not available on some plarforms like old android, so just using
2161 // log(x)/log(2) here.
2162 if (operandArray[i].getFConst() <= 0.0f)
2163 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2164 diagnostics, &resultArray[i]);
2165 else
2166 {
2167 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2168 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2169 }
2170 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302171
Olli Etuahof119a262016-08-19 15:54:22 +03002172 case EOpSqrt:
2173 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2174 if (operandArray[i].getFConst() < 0.0f)
2175 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2176 diagnostics, &resultArray[i]);
2177 else
2178 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2179 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302180
Olli Etuahof119a262016-08-19 15:54:22 +03002181 case EOpInverseSqrt:
2182 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2183 // so getting the square root first using builtin function sqrt() and then taking
2184 // its inverse.
2185 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2186 // result to 0.
2187 if (operandArray[i].getFConst() <= 0.0f)
2188 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2189 diagnostics, &resultArray[i]);
2190 else
2191 {
2192 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2193 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2194 }
2195 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302196
Olli Etuahod68924e2017-01-02 17:34:40 +00002197 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002198 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302199 resultArray[i].setBConst(!operandArray[i].getBConst());
2200 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302201
Olli Etuahof119a262016-08-19 15:54:22 +03002202 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302203 {
Olli Etuahof119a262016-08-19 15:54:22 +03002204 ASSERT(getType().getBasicType() == EbtFloat);
2205 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302206 float length = VectorLength(operandArray, objectSize);
2207 if (length)
2208 resultArray[i].setFConst(x / length);
2209 else
Olli Etuahof119a262016-08-19 15:54:22 +03002210 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2211 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302212 break;
2213 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002214 case EOpBitfieldReverse:
2215 {
2216 uint32_t value;
2217 if (getType().getBasicType() == EbtInt)
2218 {
2219 value = static_cast<uint32_t>(operandArray[i].getIConst());
2220 }
2221 else
2222 {
2223 ASSERT(getType().getBasicType() == EbtUInt);
2224 value = operandArray[i].getUConst();
2225 }
2226 uint32_t result = gl::BitfieldReverse(value);
2227 if (getType().getBasicType() == EbtInt)
2228 {
2229 resultArray[i].setIConst(static_cast<int32_t>(result));
2230 }
2231 else
2232 {
2233 resultArray[i].setUConst(result);
2234 }
2235 break;
2236 }
2237 case EOpBitCount:
2238 {
2239 uint32_t value;
2240 if (getType().getBasicType() == EbtInt)
2241 {
2242 value = static_cast<uint32_t>(operandArray[i].getIConst());
2243 }
2244 else
2245 {
2246 ASSERT(getType().getBasicType() == EbtUInt);
2247 value = operandArray[i].getUConst();
2248 }
2249 int result = gl::BitCount(value);
2250 resultArray[i].setIConst(result);
2251 break;
2252 }
2253 case EOpFindLSB:
2254 {
2255 uint32_t value;
2256 if (getType().getBasicType() == EbtInt)
2257 {
2258 value = static_cast<uint32_t>(operandArray[i].getIConst());
2259 }
2260 else
2261 {
2262 ASSERT(getType().getBasicType() == EbtUInt);
2263 value = operandArray[i].getUConst();
2264 }
2265 resultArray[i].setIConst(gl::FindLSB(value));
2266 break;
2267 }
2268 case EOpFindMSB:
2269 {
2270 uint32_t value;
2271 if (getType().getBasicType() == EbtInt)
2272 {
2273 int intValue = operandArray[i].getIConst();
2274 value = static_cast<uint32_t>(intValue);
2275 if (intValue < 0)
2276 {
2277 // Look for zero instead of one in value. This also handles the intValue ==
2278 // -1 special case, where the return value needs to be -1.
2279 value = ~value;
2280 }
2281 }
2282 else
2283 {
2284 ASSERT(getType().getBasicType() == EbtUInt);
2285 value = operandArray[i].getUConst();
2286 }
2287 resultArray[i].setIConst(gl::FindMSB(value));
2288 break;
2289 }
Olli Etuahof119a262016-08-19 15:54:22 +03002290 case EOpDFdx:
2291 case EOpDFdy:
2292 case EOpFwidth:
2293 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302294 // Derivatives of constant arguments should be 0.
2295 resultArray[i].setFConst(0.0f);
2296 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302297
Olli Etuahof119a262016-08-19 15:54:22 +03002298 default:
2299 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302300 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302301 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002302
Arun Patoleab2b9a22015-07-06 18:27:56 +05302303 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002304}
2305
Olli Etuahof119a262016-08-19 15:54:22 +03002306void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2307 FloatTypeUnaryFunc builtinFunc,
2308 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302309{
2310 ASSERT(builtinFunc);
2311
Olli Etuahof119a262016-08-19 15:54:22 +03002312 ASSERT(getType().getBasicType() == EbtFloat);
2313 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302314}
2315
Jamie Madillb1a85f42014-08-19 15:23:24 -04002316// static
Olli Etuahof119a262016-08-19 15:54:22 +03002317TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002318{
2319 ASSERT(aggregate->getSequence()->size() > 0u);
2320 size_t resultSize = aggregate->getType().getObjectSize();
2321 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2322 TBasicType basicType = aggregate->getBasicType();
2323
2324 size_t resultIndex = 0u;
2325
2326 if (aggregate->getSequence()->size() == 1u)
2327 {
2328 TIntermNode *argument = aggregate->getSequence()->front();
2329 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2330 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2331 // Check the special case of constructing a matrix diagonal from a single scalar,
2332 // or a vector from a single scalar.
2333 if (argumentConstant->getType().getObjectSize() == 1u)
2334 {
2335 if (aggregate->isMatrix())
2336 {
2337 int resultCols = aggregate->getType().getCols();
2338 int resultRows = aggregate->getType().getRows();
2339 for (int col = 0; col < resultCols; ++col)
2340 {
2341 for (int row = 0; row < resultRows; ++row)
2342 {
2343 if (col == row)
2344 {
2345 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2346 }
2347 else
2348 {
2349 resultArray[resultIndex].setFConst(0.0f);
2350 }
2351 ++resultIndex;
2352 }
2353 }
2354 }
2355 else
2356 {
2357 while (resultIndex < resultSize)
2358 {
2359 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2360 ++resultIndex;
2361 }
2362 }
2363 ASSERT(resultIndex == resultSize);
2364 return resultArray;
2365 }
2366 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2367 {
2368 // The special case of constructing a matrix from a matrix.
2369 int argumentCols = argumentConstant->getType().getCols();
2370 int argumentRows = argumentConstant->getType().getRows();
2371 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002372 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002373 for (int col = 0; col < resultCols; ++col)
2374 {
2375 for (int row = 0; row < resultRows; ++row)
2376 {
2377 if (col < argumentCols && row < argumentRows)
2378 {
2379 resultArray[resultIndex].cast(basicType,
2380 argumentUnionArray[col * argumentRows + row]);
2381 }
2382 else if (col == row)
2383 {
2384 resultArray[resultIndex].setFConst(1.0f);
2385 }
2386 else
2387 {
2388 resultArray[resultIndex].setFConst(0.0f);
2389 }
2390 ++resultIndex;
2391 }
2392 }
2393 ASSERT(resultIndex == resultSize);
2394 return resultArray;
2395 }
2396 }
2397
2398 for (TIntermNode *&argument : *aggregate->getSequence())
2399 {
2400 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2401 size_t argumentSize = argumentConstant->getType().getObjectSize();
2402 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2403 for (size_t i = 0u; i < argumentSize; ++i)
2404 {
2405 if (resultIndex >= resultSize)
2406 break;
2407 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2408 ++resultIndex;
2409 }
2410 }
2411 ASSERT(resultIndex == resultSize);
2412 return resultArray;
2413}
2414
2415// static
Olli Etuahof119a262016-08-19 15:54:22 +03002416TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2417 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302418{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002419 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302420 TIntermSequence *sequence = aggregate->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002421 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002422 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302423 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002424 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302425 TBasicType basicType = EbtVoid;
2426 TSourceLoc loc;
2427 for (unsigned int i = 0; i < paramsCount; i++)
2428 {
2429 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002430 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302431
2432 if (i == 0)
2433 {
2434 basicType = paramConstant->getType().getBasicType();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002435 loc = paramConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302436 }
2437 unionArrays[i] = paramConstant->getUnionArrayPointer();
2438 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002439 if (objectSizes[i] > maxObjectSize)
2440 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302441 }
2442
Olli Etuahod5da5052016-08-29 13:16:55 +03002443 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302444 {
2445 for (unsigned int i = 0; i < paramsCount; i++)
2446 if (objectSizes[i] != maxObjectSize)
2447 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2448 }
Arun Patole274f0702015-05-05 13:33:30 +05302449
Olli Etuahob43846e2015-06-02 18:18:57 +03002450 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002451
2452 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302453 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002454 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302455 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002456 ASSERT(basicType == EbtFloat);
2457 resultArray = new TConstantUnion[maxObjectSize];
2458 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302459 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002460 float y = unionArrays[0][i].getFConst();
2461 float x = unionArrays[1][i].getFConst();
2462 // Results are undefined if x and y are both 0.
2463 if (x == 0.0f && y == 0.0f)
2464 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2465 else
2466 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302467 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002468 break;
2469 }
Arun Patolebf790422015-05-18 17:53:04 +05302470
Olli Etuaho51182ab2017-01-22 00:12:29 +00002471 case EOpPow:
2472 {
2473 ASSERT(basicType == EbtFloat);
2474 resultArray = new TConstantUnion[maxObjectSize];
2475 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302476 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002477 float x = unionArrays[0][i].getFConst();
2478 float y = unionArrays[1][i].getFConst();
2479 // Results are undefined if x < 0.
2480 // Results are undefined if x = 0 and y <= 0.
2481 if (x < 0.0f)
2482 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2483 else if (x == 0.0f && y <= 0.0f)
2484 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2485 else
2486 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302487 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002488 break;
2489 }
Arun Patolebf790422015-05-18 17:53:04 +05302490
Olli Etuaho51182ab2017-01-22 00:12:29 +00002491 case EOpMod:
2492 {
2493 ASSERT(basicType == EbtFloat);
2494 resultArray = new TConstantUnion[maxObjectSize];
2495 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302496 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002497 float x = unionArrays[0][i].getFConst();
2498 float y = unionArrays[1][i].getFConst();
2499 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302500 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002501 break;
2502 }
Arun Patolebf790422015-05-18 17:53:04 +05302503
Olli Etuaho51182ab2017-01-22 00:12:29 +00002504 case EOpMin:
2505 {
2506 resultArray = new TConstantUnion[maxObjectSize];
2507 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302508 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002509 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302510 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002511 case EbtFloat:
2512 resultArray[i].setFConst(
2513 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2514 break;
2515 case EbtInt:
2516 resultArray[i].setIConst(
2517 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2518 break;
2519 case EbtUInt:
2520 resultArray[i].setUConst(
2521 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2522 break;
2523 default:
2524 UNREACHABLE();
2525 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302526 }
2527 }
2528 break;
Arun Patole274f0702015-05-05 13:33:30 +05302529 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002530
2531 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302532 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002533 resultArray = new TConstantUnion[maxObjectSize];
2534 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302535 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002536 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302537 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002538 case EbtFloat:
2539 resultArray[i].setFConst(
2540 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2541 break;
2542 case EbtInt:
2543 resultArray[i].setIConst(
2544 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2545 break;
2546 case EbtUInt:
2547 resultArray[i].setUConst(
2548 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2549 break;
2550 default:
2551 UNREACHABLE();
2552 break;
Arun Patole274f0702015-05-05 13:33:30 +05302553 }
2554 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002555 break;
Arun Patole274f0702015-05-05 13:33:30 +05302556 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002557
2558 case EOpStep:
2559 {
2560 ASSERT(basicType == EbtFloat);
2561 resultArray = new TConstantUnion[maxObjectSize];
2562 for (size_t i = 0; i < maxObjectSize; i++)
2563 resultArray[i].setFConst(
2564 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2565 break;
2566 }
2567
2568 case EOpLessThanComponentWise:
2569 {
2570 resultArray = new TConstantUnion[maxObjectSize];
2571 for (size_t i = 0; i < maxObjectSize; i++)
2572 {
2573 switch (basicType)
2574 {
2575 case EbtFloat:
2576 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2577 unionArrays[1][i].getFConst());
2578 break;
2579 case EbtInt:
2580 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2581 unionArrays[1][i].getIConst());
2582 break;
2583 case EbtUInt:
2584 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2585 unionArrays[1][i].getUConst());
2586 break;
2587 default:
2588 UNREACHABLE();
2589 break;
2590 }
2591 }
2592 break;
2593 }
2594
2595 case EOpLessThanEqualComponentWise:
2596 {
2597 resultArray = new TConstantUnion[maxObjectSize];
2598 for (size_t i = 0; i < maxObjectSize; i++)
2599 {
2600 switch (basicType)
2601 {
2602 case EbtFloat:
2603 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2604 unionArrays[1][i].getFConst());
2605 break;
2606 case EbtInt:
2607 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2608 unionArrays[1][i].getIConst());
2609 break;
2610 case EbtUInt:
2611 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2612 unionArrays[1][i].getUConst());
2613 break;
2614 default:
2615 UNREACHABLE();
2616 break;
2617 }
2618 }
2619 break;
2620 }
2621
2622 case EOpGreaterThanComponentWise:
2623 {
2624 resultArray = new TConstantUnion[maxObjectSize];
2625 for (size_t i = 0; i < maxObjectSize; i++)
2626 {
2627 switch (basicType)
2628 {
2629 case EbtFloat:
2630 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2631 unionArrays[1][i].getFConst());
2632 break;
2633 case EbtInt:
2634 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2635 unionArrays[1][i].getIConst());
2636 break;
2637 case EbtUInt:
2638 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2639 unionArrays[1][i].getUConst());
2640 break;
2641 default:
2642 UNREACHABLE();
2643 break;
2644 }
2645 }
2646 break;
2647 }
2648 case EOpGreaterThanEqualComponentWise:
2649 {
2650 resultArray = new TConstantUnion[maxObjectSize];
2651 for (size_t i = 0; i < maxObjectSize; i++)
2652 {
2653 switch (basicType)
2654 {
2655 case EbtFloat:
2656 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2657 unionArrays[1][i].getFConst());
2658 break;
2659 case EbtInt:
2660 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2661 unionArrays[1][i].getIConst());
2662 break;
2663 case EbtUInt:
2664 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2665 unionArrays[1][i].getUConst());
2666 break;
2667 default:
2668 UNREACHABLE();
2669 break;
2670 }
2671 }
2672 }
2673 break;
2674
2675 case EOpEqualComponentWise:
2676 {
2677 resultArray = new TConstantUnion[maxObjectSize];
2678 for (size_t i = 0; i < maxObjectSize; i++)
2679 {
2680 switch (basicType)
2681 {
2682 case EbtFloat:
2683 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2684 unionArrays[1][i].getFConst());
2685 break;
2686 case EbtInt:
2687 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2688 unionArrays[1][i].getIConst());
2689 break;
2690 case EbtUInt:
2691 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2692 unionArrays[1][i].getUConst());
2693 break;
2694 case EbtBool:
2695 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2696 unionArrays[1][i].getBConst());
2697 break;
2698 default:
2699 UNREACHABLE();
2700 break;
2701 }
2702 }
2703 break;
2704 }
2705
2706 case EOpNotEqualComponentWise:
2707 {
2708 resultArray = new TConstantUnion[maxObjectSize];
2709 for (size_t i = 0; i < maxObjectSize; i++)
2710 {
2711 switch (basicType)
2712 {
2713 case EbtFloat:
2714 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2715 unionArrays[1][i].getFConst());
2716 break;
2717 case EbtInt:
2718 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2719 unionArrays[1][i].getIConst());
2720 break;
2721 case EbtUInt:
2722 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2723 unionArrays[1][i].getUConst());
2724 break;
2725 case EbtBool:
2726 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2727 unionArrays[1][i].getBConst());
2728 break;
2729 default:
2730 UNREACHABLE();
2731 break;
2732 }
2733 }
2734 break;
2735 }
2736
2737 case EOpDistance:
2738 {
2739 ASSERT(basicType == EbtFloat);
2740 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2741 resultArray = new TConstantUnion();
2742 for (size_t i = 0; i < maxObjectSize; i++)
2743 {
2744 float x = unionArrays[0][i].getFConst();
2745 float y = unionArrays[1][i].getFConst();
2746 distanceArray[i].setFConst(x - y);
2747 }
2748 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2749 break;
2750 }
2751
2752 case EOpDot:
2753 ASSERT(basicType == EbtFloat);
2754 resultArray = new TConstantUnion();
2755 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2756 break;
2757
2758 case EOpCross:
2759 {
2760 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2761 resultArray = new TConstantUnion[maxObjectSize];
2762 float x0 = unionArrays[0][0].getFConst();
2763 float x1 = unionArrays[0][1].getFConst();
2764 float x2 = unionArrays[0][2].getFConst();
2765 float y0 = unionArrays[1][0].getFConst();
2766 float y1 = unionArrays[1][1].getFConst();
2767 float y2 = unionArrays[1][2].getFConst();
2768 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2769 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2770 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2771 break;
2772 }
2773
2774 case EOpReflect:
2775 {
2776 ASSERT(basicType == EbtFloat);
2777 // genType reflect (genType I, genType N) :
2778 // For the incident vector I and surface orientation N, returns the reflection
2779 // direction:
2780 // I - 2 * dot(N, I) * N.
2781 resultArray = new TConstantUnion[maxObjectSize];
2782 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2783 for (size_t i = 0; i < maxObjectSize; i++)
2784 {
2785 float result = unionArrays[0][i].getFConst() -
2786 2.0f * dotProduct * unionArrays[1][i].getFConst();
2787 resultArray[i].setFConst(result);
2788 }
2789 break;
2790 }
2791
2792 case EOpMulMatrixComponentWise:
2793 {
2794 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2795 (*sequence)[1]->getAsTyped()->isMatrix());
2796 // Perform component-wise matrix multiplication.
2797 resultArray = new TConstantUnion[maxObjectSize];
2798 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
2799 angle::Matrix<float> result =
2800 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2801 SetUnionArrayFromMatrix(result, resultArray);
2802 break;
2803 }
2804
2805 case EOpOuterProduct:
2806 {
2807 ASSERT(basicType == EbtFloat);
2808 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2809 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2810 resultArray = new TConstantUnion[numRows * numCols];
2811 angle::Matrix<float> result =
2812 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2813 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
2814 SetUnionArrayFromMatrix(result, resultArray);
2815 break;
2816 }
2817
2818 case EOpClamp:
2819 {
2820 resultArray = new TConstantUnion[maxObjectSize];
2821 for (size_t i = 0; i < maxObjectSize; i++)
2822 {
2823 switch (basicType)
2824 {
2825 case EbtFloat:
2826 {
2827 float x = unionArrays[0][i].getFConst();
2828 float min = unionArrays[1][i].getFConst();
2829 float max = unionArrays[2][i].getFConst();
2830 // Results are undefined if min > max.
2831 if (min > max)
2832 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2833 &resultArray[i]);
2834 else
2835 resultArray[i].setFConst(gl::clamp(x, min, max));
2836 break;
2837 }
2838
2839 case EbtInt:
2840 {
2841 int x = unionArrays[0][i].getIConst();
2842 int min = unionArrays[1][i].getIConst();
2843 int max = unionArrays[2][i].getIConst();
2844 // Results are undefined if min > max.
2845 if (min > max)
2846 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2847 &resultArray[i]);
2848 else
2849 resultArray[i].setIConst(gl::clamp(x, min, max));
2850 break;
2851 }
2852 case EbtUInt:
2853 {
2854 unsigned int x = unionArrays[0][i].getUConst();
2855 unsigned int min = unionArrays[1][i].getUConst();
2856 unsigned int max = unionArrays[2][i].getUConst();
2857 // Results are undefined if min > max.
2858 if (min > max)
2859 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2860 &resultArray[i]);
2861 else
2862 resultArray[i].setUConst(gl::clamp(x, min, max));
2863 break;
2864 }
2865 default:
2866 UNREACHABLE();
2867 break;
2868 }
2869 }
2870 break;
2871 }
2872
2873 case EOpMix:
2874 {
2875 ASSERT(basicType == EbtFloat);
2876 resultArray = new TConstantUnion[maxObjectSize];
2877 for (size_t i = 0; i < maxObjectSize; i++)
2878 {
2879 float x = unionArrays[0][i].getFConst();
2880 float y = unionArrays[1][i].getFConst();
2881 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2882 if (type == EbtFloat)
2883 {
2884 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2885 float a = unionArrays[2][i].getFConst();
2886 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2887 }
2888 else // 3rd parameter is EbtBool
2889 {
2890 ASSERT(type == EbtBool);
2891 // Selects which vector each returned component comes from.
2892 // For a component of a that is false, the corresponding component of x is
2893 // returned.
2894 // For a component of a that is true, the corresponding component of y is
2895 // returned.
2896 bool a = unionArrays[2][i].getBConst();
2897 resultArray[i].setFConst(a ? y : x);
2898 }
2899 }
2900 break;
2901 }
2902
2903 case EOpSmoothStep:
2904 {
2905 ASSERT(basicType == EbtFloat);
2906 resultArray = new TConstantUnion[maxObjectSize];
2907 for (size_t i = 0; i < maxObjectSize; i++)
2908 {
2909 float edge0 = unionArrays[0][i].getFConst();
2910 float edge1 = unionArrays[1][i].getFConst();
2911 float x = unionArrays[2][i].getFConst();
2912 // Results are undefined if edge0 >= edge1.
2913 if (edge0 >= edge1)
2914 {
2915 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2916 }
2917 else
2918 {
2919 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2920 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2921 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2922 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
2923 }
2924 }
2925 break;
2926 }
2927
2928 case EOpFaceForward:
2929 {
2930 ASSERT(basicType == EbtFloat);
2931 // genType faceforward(genType N, genType I, genType Nref) :
2932 // If dot(Nref, I) < 0 return N, otherwise return -N.
2933 resultArray = new TConstantUnion[maxObjectSize];
2934 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2935 for (size_t i = 0; i < maxObjectSize; i++)
2936 {
2937 if (dotProduct < 0)
2938 resultArray[i].setFConst(unionArrays[0][i].getFConst());
2939 else
2940 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
2941 }
2942 break;
2943 }
2944
2945 case EOpRefract:
2946 {
2947 ASSERT(basicType == EbtFloat);
2948 // genType refract(genType I, genType N, float eta) :
2949 // For the incident vector I and surface normal N, and the ratio of indices of
2950 // refraction eta,
2951 // return the refraction vector. The result is computed by
2952 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2953 // if (k < 0.0)
2954 // return genType(0.0)
2955 // else
2956 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
2957 resultArray = new TConstantUnion[maxObjectSize];
2958 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2959 for (size_t i = 0; i < maxObjectSize; i++)
2960 {
2961 float eta = unionArrays[2][i].getFConst();
2962 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2963 if (k < 0.0f)
2964 resultArray[i].setFConst(0.0f);
2965 else
2966 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
2967 (eta * dotProduct + sqrtf(k)) *
2968 unionArrays[1][i].getFConst());
2969 }
2970 break;
2971 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002972 case EOpBitfieldExtract:
2973 {
2974 resultArray = new TConstantUnion[maxObjectSize];
2975 for (size_t i = 0; i < maxObjectSize; ++i)
2976 {
2977 int offset = unionArrays[1][0].getIConst();
2978 int bits = unionArrays[2][0].getIConst();
2979 if (bits == 0)
2980 {
2981 if (aggregate->getBasicType() == EbtInt)
2982 {
2983 resultArray[i].setIConst(0);
2984 }
2985 else
2986 {
2987 ASSERT(aggregate->getBasicType() == EbtUInt);
2988 resultArray[i].setUConst(0);
2989 }
2990 }
2991 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
2992 {
2993 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
2994 &resultArray[i]);
2995 }
2996 else
2997 {
2998 // bits can be 32 here, so we need to avoid bit shift overflow.
2999 uint32_t maskMsb = 1u << (bits - 1);
3000 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3001 if (aggregate->getBasicType() == EbtInt)
3002 {
3003 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3004 uint32_t resultUnsigned = (value & mask) >> offset;
3005 if ((resultUnsigned & maskMsb) != 0)
3006 {
3007 // The most significant bits (from bits+1 to the most significant bit)
3008 // should be set to 1.
3009 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3010 resultUnsigned |= higherBitsMask;
3011 }
3012 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3013 }
3014 else
3015 {
3016 ASSERT(aggregate->getBasicType() == EbtUInt);
3017 uint32_t value = unionArrays[0][i].getUConst();
3018 resultArray[i].setUConst((value & mask) >> offset);
3019 }
3020 }
3021 }
3022 break;
3023 }
3024 case EOpBitfieldInsert:
3025 {
3026 resultArray = new TConstantUnion[maxObjectSize];
3027 for (size_t i = 0; i < maxObjectSize; ++i)
3028 {
3029 int offset = unionArrays[2][0].getIConst();
3030 int bits = unionArrays[3][0].getIConst();
3031 if (bits == 0)
3032 {
3033 if (aggregate->getBasicType() == EbtInt)
3034 {
3035 int32_t base = unionArrays[0][i].getIConst();
3036 resultArray[i].setIConst(base);
3037 }
3038 else
3039 {
3040 ASSERT(aggregate->getBasicType() == EbtUInt);
3041 uint32_t base = unionArrays[0][i].getUConst();
3042 resultArray[i].setUConst(base);
3043 }
3044 }
3045 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3046 {
3047 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3048 &resultArray[i]);
3049 }
3050 else
3051 {
3052 // bits can be 32 here, so we need to avoid bit shift overflow.
3053 uint32_t maskMsb = 1u << (bits - 1);
3054 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3055 uint32_t baseMask = ~insertMask;
3056 if (aggregate->getBasicType() == EbtInt)
3057 {
3058 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3059 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3060 uint32_t resultUnsigned =
3061 (base & baseMask) | ((insert << offset) & insertMask);
3062 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3063 }
3064 else
3065 {
3066 ASSERT(aggregate->getBasicType() == EbtUInt);
3067 uint32_t base = unionArrays[0][i].getUConst();
3068 uint32_t insert = unionArrays[1][i].getUConst();
3069 resultArray[i].setUConst((base & baseMask) |
3070 ((insert << offset) & insertMask));
3071 }
3072 }
3073 }
3074 break;
3075 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003076
3077 default:
3078 UNREACHABLE();
3079 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303080 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003081 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303082}
3083
3084// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04003085TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
3086{
3087 if (hashFunction == NULL || name.empty())
3088 return name;
3089 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
3090 TStringStream stream;
3091 stream << HASHED_NAME_PREFIX << std::hex << number;
3092 TString hashedName = stream.str();
3093 return hashedName;
3094}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003095
3096void TIntermTraverser::updateTree()
3097{
Olli Etuahoa6f22092015-05-08 18:31:10 +03003098 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
3099 {
3100 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
3101 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003102 if (!insertion.insertionsAfter.empty())
3103 {
3104 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
3105 insertion.insertionsAfter);
3106 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003107 }
3108 if (!insertion.insertionsBefore.empty())
3109 {
3110 bool inserted =
3111 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
3112 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003113 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03003114 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003115 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
3116 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003117 const NodeUpdateEntry &replacement = mReplacements[ii];
3118 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003119 bool replaced =
3120 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003121 ASSERT(replaced);
3122
Olli Etuahocd94ef92015-04-16 19:18:10 +03003123 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003124 {
3125 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03003126 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003127 // be replaced, we need to make sure we don't update the replaced
3128 // node; instead, we update the replacement node.
3129 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
3130 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003131 NodeUpdateEntry &replacement2 = mReplacements[jj];
3132 if (replacement2.parent == replacement.original)
3133 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003134 }
3135 }
3136 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003137 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
3138 {
3139 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
3140 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003141 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
3142 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003143 ASSERT(replaced);
3144 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03003145
Jamie Madill03d863c2016-07-27 18:15:53 -04003146 clearReplacementQueue();
3147}
3148
3149void TIntermTraverser::clearReplacementQueue()
3150{
Olli Etuahod4f303e2015-05-20 17:09:06 +03003151 mReplacements.clear();
3152 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04003153 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003154}
Jamie Madill1048e432016-07-23 18:51:28 -04003155
Jamie Madill03d863c2016-07-27 18:15:53 -04003156void TIntermTraverser::queueReplacement(TIntermNode *original,
3157 TIntermNode *replacement,
3158 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003159{
Jamie Madill03d863c2016-07-27 18:15:53 -04003160 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04003161}
3162
Jamie Madill03d863c2016-07-27 18:15:53 -04003163void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
3164 TIntermNode *original,
3165 TIntermNode *replacement,
3166 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003167{
Jamie Madill03d863c2016-07-27 18:15:53 -04003168 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
3169 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04003170}
Jamie Madill45bcc782016-11-07 13:58:48 -05003171
3172} // namespace sh