blob: 77c60005e30d4b5e4bfb11be75a844dcd663fd9d [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
309void TIntermAggregate::setBuiltInFunctionPrecision()
310{
311 // All built-ins returning bool should be handled as ops, not functions.
312 ASSERT(getBasicType() != EbtBool);
313
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500314 TPrecision precision = EbpUndefined;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300315 TIntermSequence::iterator childIter = mSequence.begin();
316 while (childIter != mSequence.end())
317 {
318 TIntermTyped *typed = (*childIter)->getAsTyped();
319 // ESSL spec section 8: texture functions get their precision from the sampler.
320 if (typed && IsSampler(typed->getBasicType()))
321 {
322 precision = typed->getPrecision();
323 break;
324 }
325 ++childIter;
326 }
327 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
328 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100329 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300330 mType.setPrecision(EbpHigh);
331 else
332 mType.setPrecision(precision);
333}
334
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100335void TIntermBlock::appendStatement(TIntermNode *statement)
336{
Olli Etuaho13389b62016-10-16 11:48:18 +0100337 // Declaration nodes with no children can appear if all the declarators just added constants to
338 // the symbol table instead of generating code. They're no-ops so they aren't added to blocks.
339 if (statement != nullptr && (statement->getAsDeclarationNode() == nullptr ||
340 !statement->getAsDeclarationNode()->getSequence()->empty()))
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100341 {
342 mStatements.push_back(statement);
343 }
344}
345
Olli Etuaho16c745a2017-01-16 17:02:27 +0000346void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
347{
348 ASSERT(parameter != nullptr);
349 mParameters.push_back(parameter);
350}
351
Olli Etuaho13389b62016-10-16 11:48:18 +0100352void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
353{
354 ASSERT(declarator != nullptr);
355 ASSERT(declarator->getAsSymbolNode() != nullptr ||
356 (declarator->getAsBinaryNode() != nullptr &&
357 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
358 ASSERT(mDeclarators.empty() ||
359 declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType()));
360 mDeclarators.push_back(declarator);
361}
362
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300363bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
364{
365 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
366 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
367 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
368 return false;
369}
370
Olli Etuaho57961272016-09-14 13:57:46 +0300371bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400372{
373 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100374 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
375 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400376 return false;
377}
378
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500379bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200380{
381 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100382 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200383 return false;
384}
385
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500386bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200387{
388 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
389 return false;
390}
391
Olli Etuahod7a25242015-08-18 13:49:45 +0300392TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
393{
394 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
395 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
396 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
397 mLine = node.mLine;
398}
399
Olli Etuahod4f4c112016-04-15 15:11:24 +0300400bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
401{
402 TIntermAggregate *constructor = getAsAggregate();
403 if (!constructor || !constructor->isConstructor())
404 {
405 return false;
406 }
407 for (TIntermNode *&node : *constructor->getSequence())
408 {
409 if (!node->getAsConstantUnion())
410 return false;
411 }
412 return true;
413}
414
Corentin Wallez509e4562016-08-25 14:55:44 -0400415// static
416TIntermTyped *TIntermTyped::CreateIndexNode(int index)
417{
418 TConstantUnion *u = new TConstantUnion[1];
419 u[0].setIConst(index);
420
421 TType type(EbtInt, EbpUndefined, EvqConst, 1);
422 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
423 return node;
424}
425
426// static
427TIntermTyped *TIntermTyped::CreateZero(const TType &type)
428{
429 TType constType(type);
430 constType.setQualifier(EvqConst);
431
432 if (!type.isArray() && type.getBasicType() != EbtStruct)
433 {
434 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
435
436 size_t size = constType.getObjectSize();
437 TConstantUnion *u = new TConstantUnion[size];
438 for (size_t i = 0; i < size; ++i)
439 {
440 switch (type.getBasicType())
441 {
442 case EbtFloat:
443 u[i].setFConst(0.0f);
444 break;
445 case EbtInt:
446 u[i].setIConst(0);
447 break;
448 case EbtUInt:
449 u[i].setUConst(0u);
450 break;
451 case EbtBool:
452 u[i].setBConst(false);
453 break;
454 default:
455 UNREACHABLE();
456 return nullptr;
457 }
458 }
459
460 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
461 return node;
462 }
463
464 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
465 constructor->setType(constType);
466
467 if (type.isArray())
468 {
469 TType elementType(type);
470 elementType.clearArrayness();
471
472 size_t arraySize = type.getArraySize();
473 for (size_t i = 0; i < arraySize; ++i)
474 {
475 constructor->getSequence()->push_back(CreateZero(elementType));
476 }
477 }
478 else
479 {
480 ASSERT(type.getBasicType() == EbtStruct);
481
482 TStructure *structure = type.getStruct();
483 for (const auto &field : structure->fields())
484 {
485 constructor->getSequence()->push_back(CreateZero(*field->type()));
486 }
487 }
488
489 return constructor;
490}
491
Corentin Wallez36fd1002016-12-08 11:30:44 -0500492// static
493TIntermTyped *TIntermTyped::CreateBool(bool value)
494{
495 TConstantUnion *u = new TConstantUnion[1];
496 u[0].setBConst(value);
497
498 TType type(EbtBool, EbpUndefined, EvqConst, 1);
499 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
500 return node;
501}
502
Olli Etuahod7a25242015-08-18 13:49:45 +0300503TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
504{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200505 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300506}
507
Olli Etuahobd674552016-10-06 13:28:42 +0100508void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
509{
510 setName(function.getMangledName());
511 setId(function.getUniqueId());
512}
513
Olli Etuahod7a25242015-08-18 13:49:45 +0300514TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
515 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300516 mUserDefined(node.mUserDefined),
Olli Etuahod7a25242015-08-18 13:49:45 +0300517 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100518 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
519 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300520{
521 for (TIntermNode *child : node.mSequence)
522 {
523 TIntermTyped *typedChild = child->getAsTyped();
524 ASSERT(typedChild != nullptr);
525 TIntermTyped *childCopy = typedChild->deepCopy();
526 mSequence.push_back(childCopy);
527 }
528}
529
Olli Etuahob6fa0432016-09-28 16:28:05 +0100530TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
531{
532 TIntermTyped *operandCopy = node.mOperand->deepCopy();
533 ASSERT(operandCopy != nullptr);
534 mOperand = operandCopy;
535}
536
Olli Etuahod7a25242015-08-18 13:49:45 +0300537TIntermBinary::TIntermBinary(const TIntermBinary &node)
538 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
539{
540 TIntermTyped *leftCopy = node.mLeft->deepCopy();
541 TIntermTyped *rightCopy = node.mRight->deepCopy();
542 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
543 mLeft = leftCopy;
544 mRight = rightCopy;
545}
546
547TIntermUnary::TIntermUnary(const TIntermUnary &node)
548 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
549{
550 TIntermTyped *operandCopy = node.mOperand->deepCopy();
551 ASSERT(operandCopy != nullptr);
552 mOperand = operandCopy;
553}
554
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300555TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300556{
Olli Etuahod7a25242015-08-18 13:49:45 +0300557 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300558 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
559 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300560 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300561 mCondition = conditionCopy;
562 mTrueExpression = trueCopy;
563 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300564}
565
Jamie Madillb1a85f42014-08-19 15:23:24 -0400566bool TIntermOperator::isAssignment() const
567{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300568 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400569}
570
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300571bool TIntermOperator::isMultiplication() const
572{
573 switch (mOp)
574 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500575 case EOpMul:
576 case EOpMatrixTimesMatrix:
577 case EOpMatrixTimesVector:
578 case EOpMatrixTimesScalar:
579 case EOpVectorTimesMatrix:
580 case EOpVectorTimesScalar:
581 return true;
582 default:
583 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300584 }
585}
586
Jamie Madillb1a85f42014-08-19 15:23:24 -0400587//
588// returns true if the operator is for one of the constructors
589//
590bool TIntermOperator::isConstructor() const
591{
592 switch (mOp)
593 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500594 case EOpConstructVec2:
595 case EOpConstructVec3:
596 case EOpConstructVec4:
597 case EOpConstructMat2:
598 case EOpConstructMat2x3:
599 case EOpConstructMat2x4:
600 case EOpConstructMat3x2:
601 case EOpConstructMat3:
602 case EOpConstructMat3x4:
603 case EOpConstructMat4x2:
604 case EOpConstructMat4x3:
605 case EOpConstructMat4:
606 case EOpConstructFloat:
607 case EOpConstructIVec2:
608 case EOpConstructIVec3:
609 case EOpConstructIVec4:
610 case EOpConstructInt:
611 case EOpConstructUVec2:
612 case EOpConstructUVec3:
613 case EOpConstructUVec4:
614 case EOpConstructUInt:
615 case EOpConstructBVec2:
616 case EOpConstructBVec3:
617 case EOpConstructBVec4:
618 case EOpConstructBool:
619 case EOpConstructStruct:
620 return true;
621 default:
622 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400623 }
624}
625
Olli Etuaho1dded802016-08-18 18:13:13 +0300626TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
627{
628 if (left.isMatrix())
629 {
630 if (right.isMatrix())
631 {
632 return EOpMatrixTimesMatrix;
633 }
634 else
635 {
636 if (right.isVector())
637 {
638 return EOpMatrixTimesVector;
639 }
640 else
641 {
642 return EOpMatrixTimesScalar;
643 }
644 }
645 }
646 else
647 {
648 if (right.isMatrix())
649 {
650 if (left.isVector())
651 {
652 return EOpVectorTimesMatrix;
653 }
654 else
655 {
656 return EOpMatrixTimesScalar;
657 }
658 }
659 else
660 {
661 // Neither operand is a matrix.
662 if (left.isVector() == right.isVector())
663 {
664 // Leave as component product.
665 return EOpMul;
666 }
667 else
668 {
669 return EOpVectorTimesScalar;
670 }
671 }
672 }
673}
674
675TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
676{
677 if (left.isMatrix())
678 {
679 if (right.isMatrix())
680 {
681 return EOpMatrixTimesMatrixAssign;
682 }
683 else
684 {
685 // right should be scalar, but this may not be validated yet.
686 return EOpMatrixTimesScalarAssign;
687 }
688 }
689 else
690 {
691 if (right.isMatrix())
692 {
693 // Left should be a vector, but this may not be validated yet.
694 return EOpVectorTimesMatrixAssign;
695 }
696 else
697 {
698 // Neither operand is a matrix.
699 if (left.isVector() == right.isVector())
700 {
701 // Leave as component product.
702 return EOpMulAssign;
703 }
704 else
705 {
706 // left should be vector and right should be scalar, but this may not be validated
707 // yet.
708 return EOpVectorTimesScalarAssign;
709 }
710 }
711 }
712}
713
Jamie Madillb1a85f42014-08-19 15:23:24 -0400714//
715// Make sure the type of a unary operator is appropriate for its
716// combination of operation and operand type.
717//
Olli Etuahoa2234302016-08-31 12:05:39 +0300718void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400719{
Olli Etuahoa2234302016-08-31 12:05:39 +0300720 TQualifier resultQualifier = EvqTemporary;
721 if (mOperand->getQualifier() == EvqConst)
722 resultQualifier = EvqConst;
723
724 unsigned char operandPrimarySize =
725 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400726 switch (mOp)
727 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300728 case EOpFloatBitsToInt:
729 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
730 break;
731 case EOpFloatBitsToUint:
732 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
733 break;
734 case EOpIntBitsToFloat:
735 case EOpUintBitsToFloat:
736 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
737 break;
738 case EOpPackSnorm2x16:
739 case EOpPackUnorm2x16:
740 case EOpPackHalf2x16:
741 setType(TType(EbtUInt, EbpHigh, resultQualifier));
742 break;
743 case EOpUnpackSnorm2x16:
744 case EOpUnpackUnorm2x16:
745 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
746 break;
747 case EOpUnpackHalf2x16:
748 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
749 break;
750 case EOpAny:
751 case EOpAll:
752 setType(TType(EbtBool, EbpUndefined, resultQualifier));
753 break;
754 case EOpLength:
755 case EOpDeterminant:
756 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
757 break;
758 case EOpTranspose:
759 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
760 static_cast<unsigned char>(mOperand->getType().getRows()),
761 static_cast<unsigned char>(mOperand->getType().getCols())));
762 break;
763 case EOpIsInf:
764 case EOpIsNan:
765 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
766 break;
767 default:
768 setType(mOperand->getType());
769 mType.setQualifier(resultQualifier);
770 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400771 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300772}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400773
Olli Etuahob6fa0432016-09-28 16:28:05 +0100774TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
775 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
776 mOperand(operand),
777 mSwizzleOffsets(swizzleOffsets)
778{
779 ASSERT(mSwizzleOffsets.size() <= 4);
780 promote();
781}
782
Olli Etuahoa2234302016-08-31 12:05:39 +0300783TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
784 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
785{
786 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400787}
788
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300789TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
790 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
791{
792 promote();
793}
794
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000795TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
796 : TIntermNode(), mSymbol(symbol)
797{
798 ASSERT(symbol);
799 setLine(line);
800}
801
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300802TIntermTernary::TIntermTernary(TIntermTyped *cond,
803 TIntermTyped *trueExpression,
804 TIntermTyped *falseExpression)
805 : TIntermTyped(trueExpression->getType()),
806 mCondition(cond),
807 mTrueExpression(trueExpression),
808 mFalseExpression(falseExpression)
809{
810 getTypePointer()->setQualifier(
811 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
812}
813
814// static
815TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
816 TIntermTyped *trueExpression,
817 TIntermTyped *falseExpression)
818{
819 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
820 falseExpression->getQualifier() == EvqConst)
821 {
822 return EvqConst;
823 }
824 return EvqTemporary;
825}
826
Olli Etuahob6fa0432016-09-28 16:28:05 +0100827void TIntermSwizzle::promote()
828{
829 TQualifier resultQualifier = EvqTemporary;
830 if (mOperand->getQualifier() == EvqConst)
831 resultQualifier = EvqConst;
832
833 auto numFields = mSwizzleOffsets.size();
834 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
835 static_cast<unsigned char>(numFields)));
836}
837
838bool TIntermSwizzle::hasDuplicateOffsets() const
839{
840 int offsetCount[4] = {0u, 0u, 0u, 0u};
841 for (const auto offset : mSwizzleOffsets)
842 {
843 offsetCount[offset]++;
844 if (offsetCount[offset] > 1)
845 {
846 return true;
847 }
848 }
849 return false;
850}
851
Olli Etuaho09b04a22016-12-15 13:30:26 +0000852bool TIntermSwizzle::offsetsMatch(int offset) const
853{
854 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
855}
856
Olli Etuahob6fa0432016-09-28 16:28:05 +0100857void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
858{
859 for (const int offset : mSwizzleOffsets)
860 {
861 switch (offset)
862 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500863 case 0:
864 *out << "x";
865 break;
866 case 1:
867 *out << "y";
868 break;
869 case 2:
870 *out << "z";
871 break;
872 case 3:
873 *out << "w";
874 break;
875 default:
876 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +0100877 }
878 }
879}
880
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100881TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
882 const TIntermTyped *left,
883 const TIntermTyped *right)
884{
885 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
886 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
887 right->getQualifier() != EvqConst)
888 {
889 return EvqTemporary;
890 }
891 return EvqConst;
892}
Olli Etuahob6fa0432016-09-28 16:28:05 +0100893
894// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300895void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400896{
Olli Etuaho1dded802016-08-18 18:13:13 +0300897 ASSERT(!isMultiplication() ||
898 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
899
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100900 // Comma is handled as a special case.
901 if (mOp == EOpComma)
902 {
903 setType(mRight->getType());
904 return;
905 }
906
Jamie Madillb1a85f42014-08-19 15:23:24 -0400907 // Base assumption: just make the type the same as the left
908 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400909 setType(mLeft->getType());
910
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200911 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400912 // Binary operations results in temporary variables unless both
913 // operands are const.
914 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
915 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200916 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400917 getTypePointer()->setQualifier(EvqTemporary);
918 }
919
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300920 // Handle indexing ops.
921 switch (mOp)
922 {
923 case EOpIndexDirect:
924 case EOpIndexIndirect:
925 if (mLeft->isArray())
926 {
927 mType.clearArrayness();
928 }
929 else if (mLeft->isMatrix())
930 {
931 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
932 static_cast<unsigned char>(mLeft->getRows())));
933 }
934 else if (mLeft->isVector())
935 {
936 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
937 }
938 else
939 {
940 UNREACHABLE();
941 }
942 return;
943 case EOpIndexDirectStruct:
944 {
945 const TFieldList &fields = mLeft->getType().getStruct()->fields();
946 const int i = mRight->getAsConstantUnion()->getIConst(0);
947 setType(*fields[i]->type());
948 getTypePointer()->setQualifier(resultQualifier);
949 return;
950 }
951 case EOpIndexDirectInterfaceBlock:
952 {
953 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
954 const int i = mRight->getAsConstantUnion()->getIConst(0);
955 setType(*fields[i]->type());
956 getTypePointer()->setQualifier(resultQualifier);
957 return;
958 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300959 default:
960 break;
961 }
962
963 ASSERT(mLeft->isArray() == mRight->isArray());
964
965 // The result gets promoted to the highest precision.
966 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
967 getTypePointer()->setPrecision(higherPrecision);
968
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500969 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400970
971 //
972 // All scalars or structs. Code after this test assumes this case is removed!
973 //
974 if (nominalSize == 1)
975 {
976 switch (mOp)
977 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500978 //
979 // Promote to conditional
980 //
981 case EOpEqual:
982 case EOpNotEqual:
983 case EOpLessThan:
984 case EOpGreaterThan:
985 case EOpLessThanEqual:
986 case EOpGreaterThanEqual:
987 setType(TType(EbtBool, EbpUndefined, resultQualifier));
988 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400989
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500990 //
991 // And and Or operate on conditionals
992 //
993 case EOpLogicalAnd:
994 case EOpLogicalXor:
995 case EOpLogicalOr:
996 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
997 setType(TType(EbtBool, EbpUndefined, resultQualifier));
998 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400999
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001000 default:
1001 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001002 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001003 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001004 }
1005
1006 // If we reach here, at least one of the operands is vector or matrix.
1007 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001008 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001009
Jamie Madillb1a85f42014-08-19 15:23:24 -04001010 switch (mOp)
1011 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001012 case EOpMul:
1013 break;
1014 case EOpMatrixTimesScalar:
1015 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001016 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001017 setType(TType(basicType, higherPrecision, resultQualifier,
1018 static_cast<unsigned char>(mRight->getCols()),
1019 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001020 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001021 break;
1022 case EOpMatrixTimesVector:
1023 setType(TType(basicType, higherPrecision, resultQualifier,
1024 static_cast<unsigned char>(mLeft->getRows()), 1));
1025 break;
1026 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001027 setType(TType(basicType, higherPrecision, resultQualifier,
1028 static_cast<unsigned char>(mRight->getCols()),
1029 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001030 break;
1031 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001032 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001033 static_cast<unsigned char>(nominalSize), 1));
1034 break;
1035 case EOpVectorTimesMatrix:
1036 setType(TType(basicType, higherPrecision, resultQualifier,
1037 static_cast<unsigned char>(mRight->getCols()), 1));
1038 break;
1039 case EOpMulAssign:
1040 case EOpVectorTimesScalarAssign:
1041 case EOpVectorTimesMatrixAssign:
1042 case EOpMatrixTimesScalarAssign:
1043 case EOpMatrixTimesMatrixAssign:
1044 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1045 break;
1046 case EOpAssign:
1047 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001048 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1049 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1050 break;
1051 case EOpAdd:
1052 case EOpSub:
1053 case EOpDiv:
1054 case EOpIMod:
1055 case EOpBitShiftLeft:
1056 case EOpBitShiftRight:
1057 case EOpBitwiseAnd:
1058 case EOpBitwiseXor:
1059 case EOpBitwiseOr:
1060 case EOpAddAssign:
1061 case EOpSubAssign:
1062 case EOpDivAssign:
1063 case EOpIModAssign:
1064 case EOpBitShiftLeftAssign:
1065 case EOpBitShiftRightAssign:
1066 case EOpBitwiseAndAssign:
1067 case EOpBitwiseXorAssign:
1068 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001069 {
1070 const int secondarySize =
1071 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1072 setType(TType(basicType, higherPrecision, resultQualifier,
1073 static_cast<unsigned char>(nominalSize),
1074 static_cast<unsigned char>(secondarySize)));
1075 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001076 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001077 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001078 case EOpEqual:
1079 case EOpNotEqual:
1080 case EOpLessThan:
1081 case EOpGreaterThan:
1082 case EOpLessThanEqual:
1083 case EOpGreaterThanEqual:
1084 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1085 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001086 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001087 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001088
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001089 case EOpIndexDirect:
1090 case EOpIndexIndirect:
1091 case EOpIndexDirectInterfaceBlock:
1092 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001093 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001094 UNREACHABLE();
1095 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001096 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001097 UNREACHABLE();
1098 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001099 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001100}
1101
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001102const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001103{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001104 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001105 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001106 ASSERT(index < static_cast<int>(getType().getArraySize()));
1107 TType arrayElementType = getType();
1108 arrayElementType.clearArrayness();
1109 size_t arrayElementSize = arrayElementType.getObjectSize();
1110 return &mUnionArrayPointer[arrayElementSize * index];
1111 }
1112 else if (isMatrix())
1113 {
1114 ASSERT(index < getType().getCols());
1115 int size = getType().getRows();
1116 return &mUnionArrayPointer[size * index];
1117 }
1118 else if (isVector())
1119 {
1120 ASSERT(index < getType().getNominalSize());
1121 return &mUnionArrayPointer[index];
1122 }
1123 else
1124 {
1125 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001126 return nullptr;
1127 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001128}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001129
Olli Etuahob6fa0432016-09-28 16:28:05 +01001130TIntermTyped *TIntermSwizzle::fold()
1131{
1132 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1133 if (operandConstant == nullptr)
1134 {
1135 return nullptr;
1136 }
1137
1138 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1139 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1140 {
1141 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1142 }
1143 return CreateFoldedNode(constArray, this, mType.getQualifier());
1144}
1145
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001146TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1147{
1148 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1149 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1150 switch (mOp)
1151 {
1152 case EOpIndexDirect:
1153 {
1154 if (leftConstant == nullptr || rightConstant == nullptr)
1155 {
1156 return nullptr;
1157 }
1158 int index = rightConstant->getIConst(0);
1159
1160 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1161 return CreateFoldedNode(constArray, this, mType.getQualifier());
1162 }
1163 case EOpIndexDirectStruct:
1164 {
1165 if (leftConstant == nullptr || rightConstant == nullptr)
1166 {
1167 return nullptr;
1168 }
1169 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1170 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1171
1172 size_t previousFieldsSize = 0;
1173 for (size_t i = 0; i < index; ++i)
1174 {
1175 previousFieldsSize += fields[i]->type()->getObjectSize();
1176 }
1177
1178 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1179 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1180 }
1181 case EOpIndexIndirect:
1182 case EOpIndexDirectInterfaceBlock:
1183 // Can never be constant folded.
1184 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001185 default:
1186 {
1187 if (leftConstant == nullptr || rightConstant == nullptr)
1188 {
1189 return nullptr;
1190 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001191 TConstantUnion *constArray =
1192 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001193
1194 // Nodes may be constant folded without being qualified as constant.
1195 return CreateFoldedNode(constArray, this, mType.getQualifier());
1196 }
1197 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001198}
1199
Olli Etuahof119a262016-08-19 15:54:22 +03001200TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001201{
1202 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1203 if (operandConstant == nullptr)
1204 {
1205 return nullptr;
1206 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301207
1208 TConstantUnion *constArray = nullptr;
1209 switch (mOp)
1210 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001211 case EOpAny:
1212 case EOpAll:
1213 case EOpLength:
1214 case EOpTranspose:
1215 case EOpDeterminant:
1216 case EOpInverse:
1217 case EOpPackSnorm2x16:
1218 case EOpUnpackSnorm2x16:
1219 case EOpPackUnorm2x16:
1220 case EOpUnpackUnorm2x16:
1221 case EOpPackHalf2x16:
1222 case EOpUnpackHalf2x16:
1223 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1224 break;
1225 default:
1226 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1227 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301228 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001229
1230 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001231 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001232}
1233
Olli Etuahof119a262016-08-19 15:54:22 +03001234TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001235{
1236 // Make sure that all params are constant before actual constant folding.
1237 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001238 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001239 if (param->getAsConstantUnion() == nullptr)
1240 {
1241 return nullptr;
1242 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001243 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001244 TConstantUnion *constArray = nullptr;
1245 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001246 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001247 else
Olli Etuahof119a262016-08-19 15:54:22 +03001248 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001249
1250 // Nodes may be constant folded without being qualified as constant.
1251 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
1252 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +03001253}
1254
Jamie Madillb1a85f42014-08-19 15:23:24 -04001255//
1256// The fold functions see if an operation on a constant can be done in place,
1257// without generating run-time code.
1258//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001259// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001260//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001261TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1262 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001263 TDiagnostics *diagnostics,
1264 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001265{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001266 const TConstantUnion *leftArray = getUnionArrayPointer();
1267 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001268
Olli Etuahof119a262016-08-19 15:54:22 +03001269 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001270
1271 size_t objectSize = getType().getObjectSize();
1272
1273 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1274 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1275 {
1276 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1277 }
1278 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1279 {
1280 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001281 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001282 objectSize = rightNode->getType().getObjectSize();
1283 }
1284
1285 TConstantUnion *resultArray = nullptr;
1286
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001287 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001288 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001289 case EOpAdd:
1290 resultArray = new TConstantUnion[objectSize];
1291 for (size_t i = 0; i < objectSize; i++)
1292 resultArray[i] =
1293 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1294 break;
1295 case EOpSub:
1296 resultArray = new TConstantUnion[objectSize];
1297 for (size_t i = 0; i < objectSize; i++)
1298 resultArray[i] =
1299 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1300 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001301
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001302 case EOpMul:
1303 case EOpVectorTimesScalar:
1304 case EOpMatrixTimesScalar:
1305 resultArray = new TConstantUnion[objectSize];
1306 for (size_t i = 0; i < objectSize; i++)
1307 resultArray[i] =
1308 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1309 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001310
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001311 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001312 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001313 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001314 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001315
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001316 const int leftCols = getCols();
1317 const int leftRows = getRows();
1318 const int rightCols = rightNode->getType().getCols();
1319 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001320 const int resultCols = rightCols;
1321 const int resultRows = leftRows;
1322
1323 resultArray = new TConstantUnion[resultCols * resultRows];
1324 for (int row = 0; row < resultRows; row++)
1325 {
1326 for (int column = 0; column < resultCols; column++)
1327 {
1328 resultArray[resultRows * column + row].setFConst(0.0f);
1329 for (int i = 0; i < leftCols; i++)
1330 {
1331 resultArray[resultRows * column + row].setFConst(
1332 resultArray[resultRows * column + row].getFConst() +
1333 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001334 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001335 }
1336 }
1337 }
1338 }
1339 break;
1340
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001341 case EOpDiv:
1342 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001343 {
1344 resultArray = new TConstantUnion[objectSize];
1345 for (size_t i = 0; i < objectSize; i++)
1346 {
1347 switch (getType().getBasicType())
1348 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001349 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001350 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001351 ASSERT(op == EOpDiv);
1352 float dividend = leftArray[i].getFConst();
1353 float divisor = rightArray[i].getFConst();
1354 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001355 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001356 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001357 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001358 diagnostics->warning(
1359 getLine(),
1360 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001361 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001362 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001363 }
1364 else
1365 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001366 diagnostics->warning(getLine(),
1367 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001368 bool negativeResult =
1369 std::signbit(dividend) != std::signbit(divisor);
1370 resultArray[i].setFConst(
1371 negativeResult ? -std::numeric_limits<float>::infinity()
1372 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001373 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001374 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001375 else if (gl::isInf(dividend) && gl::isInf(divisor))
1376 {
1377 diagnostics->warning(getLine(),
1378 "Infinity divided by infinity during constant "
1379 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001380 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001381 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1382 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001383 else
1384 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001385 float result = dividend / divisor;
1386 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001387 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001388 diagnostics->warning(
1389 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001390 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001391 }
1392 resultArray[i].setFConst(result);
1393 }
1394 break;
1395 }
1396 case EbtInt:
1397 if (rightArray[i] == 0)
1398 {
1399 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001400 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001401 resultArray[i].setIConst(INT_MAX);
1402 }
1403 else
1404 {
1405 int lhs = leftArray[i].getIConst();
1406 int divisor = rightArray[i].getIConst();
1407 if (op == EOpDiv)
1408 {
1409 // Check for the special case where the minimum representable number
1410 // is
1411 // divided by -1. If left alone this leads to integer overflow in
1412 // C++.
1413 // ESSL 3.00.6 section 4.1.3 Integers:
1414 // "However, for the case where the minimum representable value is
1415 // divided by -1, it is allowed to return either the minimum
1416 // representable value or the maximum representable value."
1417 if (lhs == -0x7fffffff - 1 && divisor == -1)
1418 {
1419 resultArray[i].setIConst(0x7fffffff);
1420 }
1421 else
1422 {
1423 resultArray[i].setIConst(lhs / divisor);
1424 }
Olli Etuahod4453572016-09-27 13:21:46 +01001425 }
1426 else
1427 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001428 ASSERT(op == EOpIMod);
1429 if (lhs < 0 || divisor < 0)
1430 {
1431 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1432 // when
1433 // either one of the operands is negative.
1434 diagnostics->warning(getLine(),
1435 "Negative modulus operator operand "
1436 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001437 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001438 resultArray[i].setIConst(0);
1439 }
1440 else
1441 {
1442 resultArray[i].setIConst(lhs % divisor);
1443 }
Olli Etuahod4453572016-09-27 13:21:46 +01001444 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001445 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001446 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001447
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001448 case EbtUInt:
1449 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001450 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001451 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001452 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001453 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001454 }
1455 else
1456 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001457 if (op == EOpDiv)
1458 {
1459 resultArray[i].setUConst(leftArray[i].getUConst() /
1460 rightArray[i].getUConst());
1461 }
1462 else
1463 {
1464 ASSERT(op == EOpIMod);
1465 resultArray[i].setUConst(leftArray[i].getUConst() %
1466 rightArray[i].getUConst());
1467 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001468 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001469 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001470
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001471 default:
1472 UNREACHABLE();
1473 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001474 }
1475 }
1476 }
1477 break;
1478
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001479 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001480 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001481 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001482 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001483
1484 const int matrixCols = getCols();
1485 const int matrixRows = getRows();
1486
1487 resultArray = new TConstantUnion[matrixRows];
1488
1489 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1490 {
1491 resultArray[matrixRow].setFConst(0.0f);
1492 for (int col = 0; col < matrixCols; col++)
1493 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001494 resultArray[matrixRow].setFConst(
1495 resultArray[matrixRow].getFConst() +
1496 leftArray[col * matrixRows + matrixRow].getFConst() *
1497 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001498 }
1499 }
1500 }
1501 break;
1502
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001503 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001504 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001505 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001506 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001507
1508 const int matrixCols = rightNode->getType().getCols();
1509 const int matrixRows = rightNode->getType().getRows();
1510
1511 resultArray = new TConstantUnion[matrixCols];
1512
1513 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1514 {
1515 resultArray[matrixCol].setFConst(0.0f);
1516 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1517 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001518 resultArray[matrixCol].setFConst(
1519 resultArray[matrixCol].getFConst() +
1520 leftArray[matrixRow].getFConst() *
1521 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001522 }
1523 }
1524 }
1525 break;
1526
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001527 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001528 {
1529 resultArray = new TConstantUnion[objectSize];
1530 for (size_t i = 0; i < objectSize; i++)
1531 {
1532 resultArray[i] = leftArray[i] && rightArray[i];
1533 }
1534 }
1535 break;
1536
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001537 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001538 {
1539 resultArray = new TConstantUnion[objectSize];
1540 for (size_t i = 0; i < objectSize; i++)
1541 {
1542 resultArray[i] = leftArray[i] || rightArray[i];
1543 }
1544 }
1545 break;
1546
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001547 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001548 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001549 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001550 resultArray = new TConstantUnion[objectSize];
1551 for (size_t i = 0; i < objectSize; i++)
1552 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001553 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001554 }
1555 }
1556 break;
1557
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001558 case EOpBitwiseAnd:
1559 resultArray = new TConstantUnion[objectSize];
1560 for (size_t i = 0; i < objectSize; i++)
1561 resultArray[i] = leftArray[i] & rightArray[i];
1562 break;
1563 case EOpBitwiseXor:
1564 resultArray = new TConstantUnion[objectSize];
1565 for (size_t i = 0; i < objectSize; i++)
1566 resultArray[i] = leftArray[i] ^ rightArray[i];
1567 break;
1568 case EOpBitwiseOr:
1569 resultArray = new TConstantUnion[objectSize];
1570 for (size_t i = 0; i < objectSize; i++)
1571 resultArray[i] = leftArray[i] | rightArray[i];
1572 break;
1573 case EOpBitShiftLeft:
1574 resultArray = new TConstantUnion[objectSize];
1575 for (size_t i = 0; i < objectSize; i++)
1576 resultArray[i] =
1577 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1578 break;
1579 case EOpBitShiftRight:
1580 resultArray = new TConstantUnion[objectSize];
1581 for (size_t i = 0; i < objectSize; i++)
1582 resultArray[i] =
1583 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1584 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001585
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001586 case EOpLessThan:
1587 ASSERT(objectSize == 1);
1588 resultArray = new TConstantUnion[1];
1589 resultArray->setBConst(*leftArray < *rightArray);
1590 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001591
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001592 case EOpGreaterThan:
1593 ASSERT(objectSize == 1);
1594 resultArray = new TConstantUnion[1];
1595 resultArray->setBConst(*leftArray > *rightArray);
1596 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001597
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001598 case EOpLessThanEqual:
1599 ASSERT(objectSize == 1);
1600 resultArray = new TConstantUnion[1];
1601 resultArray->setBConst(!(*leftArray > *rightArray));
1602 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001603
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001604 case EOpGreaterThanEqual:
1605 ASSERT(objectSize == 1);
1606 resultArray = new TConstantUnion[1];
1607 resultArray->setBConst(!(*leftArray < *rightArray));
1608 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001609
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001610 case EOpEqual:
1611 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001612 {
1613 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001614 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001615 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001616 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001617 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001618 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001619 equal = false;
1620 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001621 }
1622 }
1623 if (op == EOpEqual)
1624 {
1625 resultArray->setBConst(equal);
1626 }
1627 else
1628 {
1629 resultArray->setBConst(!equal);
1630 }
1631 }
1632 break;
1633
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001634 default:
1635 UNREACHABLE();
1636 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001637 }
1638 return resultArray;
1639}
1640
Olli Etuahof119a262016-08-19 15:54:22 +03001641// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1642// code. Returns the constant value to keep using. Nullptr should not be returned.
1643TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001644{
Olli Etuahof119a262016-08-19 15:54:22 +03001645 // Do operations where the return type may have a different number of components compared to the
1646 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001647
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001648 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001649 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301650
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001651 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301652 TConstantUnion *resultArray = nullptr;
1653 switch (op)
1654 {
Olli Etuahof119a262016-08-19 15:54:22 +03001655 case EOpAny:
1656 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301657 resultArray = new TConstantUnion();
1658 resultArray->setBConst(false);
1659 for (size_t i = 0; i < objectSize; i++)
1660 {
1661 if (operandArray[i].getBConst())
1662 {
1663 resultArray->setBConst(true);
1664 break;
1665 }
1666 }
1667 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301668
Olli Etuahof119a262016-08-19 15:54:22 +03001669 case EOpAll:
1670 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301671 resultArray = new TConstantUnion();
1672 resultArray->setBConst(true);
1673 for (size_t i = 0; i < objectSize; i++)
1674 {
1675 if (!operandArray[i].getBConst())
1676 {
1677 resultArray->setBConst(false);
1678 break;
1679 }
1680 }
1681 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301682
Olli Etuahof119a262016-08-19 15:54:22 +03001683 case EOpLength:
1684 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301685 resultArray = new TConstantUnion();
1686 resultArray->setFConst(VectorLength(operandArray, objectSize));
1687 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301688
Olli Etuahof119a262016-08-19 15:54:22 +03001689 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301690 {
Olli Etuahof119a262016-08-19 15:54:22 +03001691 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301692 resultArray = new TConstantUnion[objectSize];
1693 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001694 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301695 SetUnionArrayFromMatrix(result, resultArray);
1696 break;
1697 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301698
Olli Etuahof119a262016-08-19 15:54:22 +03001699 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301700 {
Olli Etuahof119a262016-08-19 15:54:22 +03001701 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301702 unsigned int size = getType().getNominalSize();
1703 ASSERT(size >= 2 && size <= 4);
1704 resultArray = new TConstantUnion();
1705 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1706 break;
1707 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301708
Olli Etuahof119a262016-08-19 15:54:22 +03001709 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301710 {
Olli Etuahof119a262016-08-19 15:54:22 +03001711 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301712 unsigned int size = getType().getNominalSize();
1713 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001714 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301715 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1716 SetUnionArrayFromMatrix(result, resultArray);
1717 break;
1718 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301719
Olli Etuahof119a262016-08-19 15:54:22 +03001720 case EOpPackSnorm2x16:
1721 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301722 ASSERT(getType().getNominalSize() == 2);
1723 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001724 resultArray->setUConst(
1725 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301726 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301727
Olli Etuahof119a262016-08-19 15:54:22 +03001728 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301729 {
Olli Etuahof119a262016-08-19 15:54:22 +03001730 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301731 resultArray = new TConstantUnion[2];
1732 float f1, f2;
1733 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1734 resultArray[0].setFConst(f1);
1735 resultArray[1].setFConst(f2);
1736 break;
1737 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301738
Olli Etuahof119a262016-08-19 15:54:22 +03001739 case EOpPackUnorm2x16:
1740 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301741 ASSERT(getType().getNominalSize() == 2);
1742 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001743 resultArray->setUConst(
1744 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301745 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301746
Olli Etuahof119a262016-08-19 15:54:22 +03001747 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301748 {
Olli Etuahof119a262016-08-19 15:54:22 +03001749 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301750 resultArray = new TConstantUnion[2];
1751 float f1, f2;
1752 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1753 resultArray[0].setFConst(f1);
1754 resultArray[1].setFConst(f2);
1755 break;
1756 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301757
Olli Etuahof119a262016-08-19 15:54:22 +03001758 case EOpPackHalf2x16:
1759 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301760 ASSERT(getType().getNominalSize() == 2);
1761 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001762 resultArray->setUConst(
1763 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301764 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301765
Olli Etuahof119a262016-08-19 15:54:22 +03001766 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301767 {
Olli Etuahof119a262016-08-19 15:54:22 +03001768 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301769 resultArray = new TConstantUnion[2];
1770 float f1, f2;
1771 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1772 resultArray[0].setFConst(f1);
1773 resultArray[1].setFConst(f2);
1774 break;
1775 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301776
Olli Etuahof119a262016-08-19 15:54:22 +03001777 default:
1778 UNREACHABLE();
1779 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301780 }
1781
1782 return resultArray;
1783}
1784
Olli Etuahof119a262016-08-19 15:54:22 +03001785TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1786 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301787{
Olli Etuahof119a262016-08-19 15:54:22 +03001788 // Do unary operations where each component of the result is computed based on the corresponding
1789 // component of the operand. Also folds normalize, though the divisor in that case takes all
1790 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301791
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001792 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001793 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001794
1795 size_t objectSize = getType().getObjectSize();
1796
Arun Patoleab2b9a22015-07-06 18:27:56 +05301797 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1798 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301799 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001800 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301801 {
Olli Etuahof119a262016-08-19 15:54:22 +03001802 case EOpNegative:
1803 switch (getType().getBasicType())
1804 {
1805 case EbtFloat:
1806 resultArray[i].setFConst(-operandArray[i].getFConst());
1807 break;
1808 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001809 if (operandArray[i] == std::numeric_limits<int>::min())
1810 {
1811 // The minimum representable integer doesn't have a positive
1812 // counterpart, rather the negation overflows and in ESSL is supposed to
1813 // wrap back to the minimum representable integer. Make sure that we
1814 // don't actually let the negation overflow, which has undefined
1815 // behavior in C++.
1816 resultArray[i].setIConst(std::numeric_limits<int>::min());
1817 }
1818 else
1819 {
1820 resultArray[i].setIConst(-operandArray[i].getIConst());
1821 }
Olli Etuahof119a262016-08-19 15:54:22 +03001822 break;
1823 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001824 if (operandArray[i] == 0x80000000u)
1825 {
1826 resultArray[i].setUConst(0x80000000u);
1827 }
1828 else
1829 {
1830 resultArray[i].setUConst(static_cast<unsigned int>(
1831 -static_cast<int>(operandArray[i].getUConst())));
1832 }
Olli Etuahof119a262016-08-19 15:54:22 +03001833 break;
1834 default:
1835 UNREACHABLE();
1836 return nullptr;
1837 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301838 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301839
Olli Etuahof119a262016-08-19 15:54:22 +03001840 case EOpPositive:
1841 switch (getType().getBasicType())
1842 {
1843 case EbtFloat:
1844 resultArray[i].setFConst(operandArray[i].getFConst());
1845 break;
1846 case EbtInt:
1847 resultArray[i].setIConst(operandArray[i].getIConst());
1848 break;
1849 case EbtUInt:
1850 resultArray[i].setUConst(static_cast<unsigned int>(
1851 static_cast<int>(operandArray[i].getUConst())));
1852 break;
1853 default:
1854 UNREACHABLE();
1855 return nullptr;
1856 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301857 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301858
Olli Etuahof119a262016-08-19 15:54:22 +03001859 case EOpLogicalNot:
1860 switch (getType().getBasicType())
1861 {
1862 case EbtBool:
1863 resultArray[i].setBConst(!operandArray[i].getBConst());
1864 break;
1865 default:
1866 UNREACHABLE();
1867 return nullptr;
1868 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301869 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301870
Olli Etuahof119a262016-08-19 15:54:22 +03001871 case EOpBitwiseNot:
1872 switch (getType().getBasicType())
1873 {
1874 case EbtInt:
1875 resultArray[i].setIConst(~operandArray[i].getIConst());
1876 break;
1877 case EbtUInt:
1878 resultArray[i].setUConst(~operandArray[i].getUConst());
1879 break;
1880 default:
1881 UNREACHABLE();
1882 return nullptr;
1883 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301884 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301885
Olli Etuahof119a262016-08-19 15:54:22 +03001886 case EOpRadians:
1887 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301888 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1889 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301890
Olli Etuahof119a262016-08-19 15:54:22 +03001891 case EOpDegrees:
1892 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301893 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1894 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301895
Olli Etuahof119a262016-08-19 15:54:22 +03001896 case EOpSin:
1897 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301898 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301899
Olli Etuahof119a262016-08-19 15:54:22 +03001900 case EOpCos:
1901 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1902 break;
1903
1904 case EOpTan:
1905 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1906 break;
1907
1908 case EOpAsin:
1909 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1910 // 0.
1911 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1912 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1913 diagnostics, &resultArray[i]);
1914 else
1915 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1916 break;
1917
1918 case EOpAcos:
1919 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1920 // 0.
1921 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1922 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1923 diagnostics, &resultArray[i]);
1924 else
1925 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1926 break;
1927
1928 case EOpAtan:
1929 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1930 break;
1931
1932 case EOpSinh:
1933 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1934 break;
1935
1936 case EOpCosh:
1937 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1938 break;
1939
1940 case EOpTanh:
1941 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
1942 break;
1943
1944 case EOpAsinh:
1945 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
1946 break;
1947
1948 case EOpAcosh:
1949 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1950 if (operandArray[i].getFConst() < 1.0f)
1951 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1952 diagnostics, &resultArray[i]);
1953 else
1954 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
1955 break;
1956
1957 case EOpAtanh:
1958 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
1959 // 0.
1960 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
1961 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1962 diagnostics, &resultArray[i]);
1963 else
1964 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
1965 break;
1966
1967 case EOpAbs:
1968 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301969 {
Olli Etuahof119a262016-08-19 15:54:22 +03001970 case EbtFloat:
1971 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1972 break;
1973 case EbtInt:
1974 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1975 break;
1976 default:
1977 UNREACHABLE();
1978 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301979 }
1980 break;
Olli Etuahof119a262016-08-19 15:54:22 +03001981
1982 case EOpSign:
1983 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301984 {
Olli Etuahof119a262016-08-19 15:54:22 +03001985 case EbtFloat:
1986 {
1987 float fConst = operandArray[i].getFConst();
1988 float fResult = 0.0f;
1989 if (fConst > 0.0f)
1990 fResult = 1.0f;
1991 else if (fConst < 0.0f)
1992 fResult = -1.0f;
1993 resultArray[i].setFConst(fResult);
1994 break;
1995 }
1996 case EbtInt:
1997 {
1998 int iConst = operandArray[i].getIConst();
1999 int iResult = 0;
2000 if (iConst > 0)
2001 iResult = 1;
2002 else if (iConst < 0)
2003 iResult = -1;
2004 resultArray[i].setIConst(iResult);
2005 break;
2006 }
2007 default:
2008 UNREACHABLE();
2009 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302010 }
2011 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302012
Olli Etuahof119a262016-08-19 15:54:22 +03002013 case EOpFloor:
2014 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2015 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302016
Olli Etuahof119a262016-08-19 15:54:22 +03002017 case EOpTrunc:
2018 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2019 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302020
Olli Etuahof119a262016-08-19 15:54:22 +03002021 case EOpRound:
2022 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2023 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302024
Olli Etuahof119a262016-08-19 15:54:22 +03002025 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302026 {
Olli Etuahof119a262016-08-19 15:54:22 +03002027 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302028 float x = operandArray[i].getFConst();
2029 float result;
2030 float fractPart = modff(x, &result);
2031 if (fabsf(fractPart) == 0.5f)
2032 result = 2.0f * roundf(x / 2.0f);
2033 else
2034 result = roundf(x);
2035 resultArray[i].setFConst(result);
2036 break;
2037 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302038
Olli Etuahof119a262016-08-19 15:54:22 +03002039 case EOpCeil:
2040 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2041 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302042
Olli Etuahof119a262016-08-19 15:54:22 +03002043 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302044 {
Olli Etuahof119a262016-08-19 15:54:22 +03002045 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302046 float x = operandArray[i].getFConst();
2047 resultArray[i].setFConst(x - floorf(x));
2048 break;
2049 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302050
Olli Etuahof119a262016-08-19 15:54:22 +03002051 case EOpIsNan:
2052 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302053 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2054 break;
Arun Patole551279e2015-07-07 18:18:23 +05302055
Olli Etuahof119a262016-08-19 15:54:22 +03002056 case EOpIsInf:
2057 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302058 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2059 break;
Arun Patole551279e2015-07-07 18:18:23 +05302060
Olli Etuahof119a262016-08-19 15:54:22 +03002061 case EOpFloatBitsToInt:
2062 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302063 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2064 break;
Arun Patole551279e2015-07-07 18:18:23 +05302065
Olli Etuahof119a262016-08-19 15:54:22 +03002066 case EOpFloatBitsToUint:
2067 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302068 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2069 break;
Arun Patole551279e2015-07-07 18:18:23 +05302070
Olli Etuahof119a262016-08-19 15:54:22 +03002071 case EOpIntBitsToFloat:
2072 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302073 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2074 break;
Arun Patole551279e2015-07-07 18:18:23 +05302075
Olli Etuahof119a262016-08-19 15:54:22 +03002076 case EOpUintBitsToFloat:
2077 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302078 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2079 break;
Arun Patole551279e2015-07-07 18:18:23 +05302080
Olli Etuahof119a262016-08-19 15:54:22 +03002081 case EOpExp:
2082 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2083 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302084
Olli Etuahof119a262016-08-19 15:54:22 +03002085 case EOpLog:
2086 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2087 if (operandArray[i].getFConst() <= 0.0f)
2088 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2089 diagnostics, &resultArray[i]);
2090 else
2091 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2092 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302093
Olli Etuahof119a262016-08-19 15:54:22 +03002094 case EOpExp2:
2095 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2096 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302097
Olli Etuahof119a262016-08-19 15:54:22 +03002098 case EOpLog2:
2099 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2100 // And log2f is not available on some plarforms like old android, so just using
2101 // log(x)/log(2) here.
2102 if (operandArray[i].getFConst() <= 0.0f)
2103 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2104 diagnostics, &resultArray[i]);
2105 else
2106 {
2107 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2108 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2109 }
2110 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302111
Olli Etuahof119a262016-08-19 15:54:22 +03002112 case EOpSqrt:
2113 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2114 if (operandArray[i].getFConst() < 0.0f)
2115 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2116 diagnostics, &resultArray[i]);
2117 else
2118 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2119 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302120
Olli Etuahof119a262016-08-19 15:54:22 +03002121 case EOpInverseSqrt:
2122 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2123 // so getting the square root first using builtin function sqrt() and then taking
2124 // its inverse.
2125 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2126 // result to 0.
2127 if (operandArray[i].getFConst() <= 0.0f)
2128 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2129 diagnostics, &resultArray[i]);
2130 else
2131 {
2132 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2133 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2134 }
2135 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136
Olli Etuahod68924e2017-01-02 17:34:40 +00002137 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002138 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302139 resultArray[i].setBConst(!operandArray[i].getBConst());
2140 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302141
Olli Etuahof119a262016-08-19 15:54:22 +03002142 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302143 {
Olli Etuahof119a262016-08-19 15:54:22 +03002144 ASSERT(getType().getBasicType() == EbtFloat);
2145 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302146 float length = VectorLength(operandArray, objectSize);
2147 if (length)
2148 resultArray[i].setFConst(x / length);
2149 else
Olli Etuahof119a262016-08-19 15:54:22 +03002150 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2151 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302152 break;
2153 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302154
Olli Etuahof119a262016-08-19 15:54:22 +03002155 case EOpDFdx:
2156 case EOpDFdy:
2157 case EOpFwidth:
2158 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302159 // Derivatives of constant arguments should be 0.
2160 resultArray[i].setFConst(0.0f);
2161 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302162
Olli Etuahof119a262016-08-19 15:54:22 +03002163 default:
2164 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302165 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302166 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002167
Arun Patoleab2b9a22015-07-06 18:27:56 +05302168 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002169}
2170
Olli Etuahof119a262016-08-19 15:54:22 +03002171void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2172 FloatTypeUnaryFunc builtinFunc,
2173 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302174{
2175 ASSERT(builtinFunc);
2176
Olli Etuahof119a262016-08-19 15:54:22 +03002177 ASSERT(getType().getBasicType() == EbtFloat);
2178 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302179}
2180
Jamie Madillb1a85f42014-08-19 15:23:24 -04002181// static
Olli Etuahof119a262016-08-19 15:54:22 +03002182TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002183{
2184 ASSERT(aggregate->getSequence()->size() > 0u);
2185 size_t resultSize = aggregate->getType().getObjectSize();
2186 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2187 TBasicType basicType = aggregate->getBasicType();
2188
2189 size_t resultIndex = 0u;
2190
2191 if (aggregate->getSequence()->size() == 1u)
2192 {
2193 TIntermNode *argument = aggregate->getSequence()->front();
2194 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2195 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2196 // Check the special case of constructing a matrix diagonal from a single scalar,
2197 // or a vector from a single scalar.
2198 if (argumentConstant->getType().getObjectSize() == 1u)
2199 {
2200 if (aggregate->isMatrix())
2201 {
2202 int resultCols = aggregate->getType().getCols();
2203 int resultRows = aggregate->getType().getRows();
2204 for (int col = 0; col < resultCols; ++col)
2205 {
2206 for (int row = 0; row < resultRows; ++row)
2207 {
2208 if (col == row)
2209 {
2210 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2211 }
2212 else
2213 {
2214 resultArray[resultIndex].setFConst(0.0f);
2215 }
2216 ++resultIndex;
2217 }
2218 }
2219 }
2220 else
2221 {
2222 while (resultIndex < resultSize)
2223 {
2224 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2225 ++resultIndex;
2226 }
2227 }
2228 ASSERT(resultIndex == resultSize);
2229 return resultArray;
2230 }
2231 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2232 {
2233 // The special case of constructing a matrix from a matrix.
2234 int argumentCols = argumentConstant->getType().getCols();
2235 int argumentRows = argumentConstant->getType().getRows();
2236 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002237 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002238 for (int col = 0; col < resultCols; ++col)
2239 {
2240 for (int row = 0; row < resultRows; ++row)
2241 {
2242 if (col < argumentCols && row < argumentRows)
2243 {
2244 resultArray[resultIndex].cast(basicType,
2245 argumentUnionArray[col * argumentRows + row]);
2246 }
2247 else if (col == row)
2248 {
2249 resultArray[resultIndex].setFConst(1.0f);
2250 }
2251 else
2252 {
2253 resultArray[resultIndex].setFConst(0.0f);
2254 }
2255 ++resultIndex;
2256 }
2257 }
2258 ASSERT(resultIndex == resultSize);
2259 return resultArray;
2260 }
2261 }
2262
2263 for (TIntermNode *&argument : *aggregate->getSequence())
2264 {
2265 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2266 size_t argumentSize = argumentConstant->getType().getObjectSize();
2267 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2268 for (size_t i = 0u; i < argumentSize; ++i)
2269 {
2270 if (resultIndex >= resultSize)
2271 break;
2272 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2273 ++resultIndex;
2274 }
2275 }
2276 ASSERT(resultIndex == resultSize);
2277 return resultArray;
2278}
2279
2280// static
Olli Etuahof119a262016-08-19 15:54:22 +03002281TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2282 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302283{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002284 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302285 TIntermSequence *sequence = aggregate->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002286 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002287 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302288 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002289 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302290 TBasicType basicType = EbtVoid;
2291 TSourceLoc loc;
2292 for (unsigned int i = 0; i < paramsCount; i++)
2293 {
2294 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002295 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302296
2297 if (i == 0)
2298 {
2299 basicType = paramConstant->getType().getBasicType();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002300 loc = paramConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302301 }
2302 unionArrays[i] = paramConstant->getUnionArrayPointer();
2303 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002304 if (objectSizes[i] > maxObjectSize)
2305 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302306 }
2307
Olli Etuahod5da5052016-08-29 13:16:55 +03002308 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302309 {
2310 for (unsigned int i = 0; i < paramsCount; i++)
2311 if (objectSizes[i] != maxObjectSize)
2312 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2313 }
Arun Patole274f0702015-05-05 13:33:30 +05302314
Olli Etuahob43846e2015-06-02 18:18:57 +03002315 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302316 if (paramsCount == 2)
2317 {
2318 //
2319 // Binary built-in
2320 //
2321 switch (op)
2322 {
Olli Etuahof119a262016-08-19 15:54:22 +03002323 case EOpAtan:
Arun Patolebf790422015-05-18 17:53:04 +05302324 {
Olli Etuahof119a262016-08-19 15:54:22 +03002325 ASSERT(basicType == EbtFloat);
2326 resultArray = new TConstantUnion[maxObjectSize];
2327 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302328 {
Olli Etuahof119a262016-08-19 15:54:22 +03002329 float y = unionArrays[0][i].getFConst();
2330 float x = unionArrays[1][i].getFConst();
2331 // Results are undefined if x and y are both 0.
2332 if (x == 0.0f && y == 0.0f)
2333 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2334 &resultArray[i]);
2335 else
2336 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302337 }
Olli Etuahof119a262016-08-19 15:54:22 +03002338 break;
Arun Patolebf790422015-05-18 17:53:04 +05302339 }
Arun Patolebf790422015-05-18 17:53:04 +05302340
Olli Etuahof119a262016-08-19 15:54:22 +03002341 case EOpPow:
Arun Patolebf790422015-05-18 17:53:04 +05302342 {
Olli Etuahof119a262016-08-19 15:54:22 +03002343 ASSERT(basicType == EbtFloat);
2344 resultArray = new TConstantUnion[maxObjectSize];
2345 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302346 {
Olli Etuahof119a262016-08-19 15:54:22 +03002347 float x = unionArrays[0][i].getFConst();
2348 float y = unionArrays[1][i].getFConst();
2349 // Results are undefined if x < 0.
2350 // Results are undefined if x = 0 and y <= 0.
2351 if (x < 0.0f)
2352 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2353 &resultArray[i]);
2354 else if (x == 0.0f && y <= 0.0f)
2355 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2356 &resultArray[i]);
2357 else
2358 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302359 }
Olli Etuahof119a262016-08-19 15:54:22 +03002360 break;
Arun Patolebf790422015-05-18 17:53:04 +05302361 }
Arun Patolebf790422015-05-18 17:53:04 +05302362
Olli Etuahof119a262016-08-19 15:54:22 +03002363 case EOpMod:
Arun Patolebf790422015-05-18 17:53:04 +05302364 {
Olli Etuahof119a262016-08-19 15:54:22 +03002365 ASSERT(basicType == EbtFloat);
2366 resultArray = new TConstantUnion[maxObjectSize];
2367 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302368 {
Olli Etuahof119a262016-08-19 15:54:22 +03002369 float x = unionArrays[0][i].getFConst();
2370 float y = unionArrays[1][i].getFConst();
2371 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302372 }
Olli Etuahof119a262016-08-19 15:54:22 +03002373 break;
Arun Patolebf790422015-05-18 17:53:04 +05302374 }
Arun Patolebf790422015-05-18 17:53:04 +05302375
Olli Etuahof119a262016-08-19 15:54:22 +03002376 case EOpMin:
Arun Patole274f0702015-05-05 13:33:30 +05302377 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002378 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302379 for (size_t i = 0; i < maxObjectSize; i++)
2380 {
2381 switch (basicType)
2382 {
Olli Etuahof119a262016-08-19 15:54:22 +03002383 case EbtFloat:
2384 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
2385 unionArrays[1][i].getFConst()));
2386 break;
2387 case EbtInt:
2388 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
2389 unionArrays[1][i].getIConst()));
2390 break;
2391 case EbtUInt:
2392 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
2393 unionArrays[1][i].getUConst()));
2394 break;
2395 default:
2396 UNREACHABLE();
2397 break;
Arun Patole274f0702015-05-05 13:33:30 +05302398 }
2399 }
Olli Etuahof119a262016-08-19 15:54:22 +03002400 break;
Arun Patole274f0702015-05-05 13:33:30 +05302401 }
Arun Patole274f0702015-05-05 13:33:30 +05302402
Olli Etuahof119a262016-08-19 15:54:22 +03002403 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302404 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002405 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302406 for (size_t i = 0; i < maxObjectSize; i++)
2407 {
2408 switch (basicType)
2409 {
Olli Etuahof119a262016-08-19 15:54:22 +03002410 case EbtFloat:
2411 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
2412 unionArrays[1][i].getFConst()));
2413 break;
2414 case EbtInt:
2415 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
2416 unionArrays[1][i].getIConst()));
2417 break;
2418 case EbtUInt:
2419 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
2420 unionArrays[1][i].getUConst()));
2421 break;
2422 default:
2423 UNREACHABLE();
2424 break;
Arun Patole274f0702015-05-05 13:33:30 +05302425 }
2426 }
Olli Etuahof119a262016-08-19 15:54:22 +03002427 break;
Arun Patole274f0702015-05-05 13:33:30 +05302428 }
Arun Patole274f0702015-05-05 13:33:30 +05302429
Olli Etuahof119a262016-08-19 15:54:22 +03002430 case EOpStep:
Arun Patolebf790422015-05-18 17:53:04 +05302431 {
Olli Etuahof119a262016-08-19 15:54:22 +03002432 ASSERT(basicType == EbtFloat);
2433 resultArray = new TConstantUnion[maxObjectSize];
2434 for (size_t i = 0; i < maxObjectSize; i++)
2435 resultArray[i].setFConst(
2436 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
2437 : 1.0f);
2438 break;
Arun Patolebf790422015-05-18 17:53:04 +05302439 }
Arun Patolebf790422015-05-18 17:53:04 +05302440
Olli Etuahoe1805592017-01-02 16:41:20 +00002441 case EOpLessThanComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302442 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002443 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302444 for (size_t i = 0; i < maxObjectSize; i++)
2445 {
2446 switch (basicType)
2447 {
Olli Etuahof119a262016-08-19 15:54:22 +03002448 case EbtFloat:
2449 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2450 unionArrays[1][i].getFConst());
2451 break;
2452 case EbtInt:
2453 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2454 unionArrays[1][i].getIConst());
2455 break;
2456 case EbtUInt:
2457 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2458 unionArrays[1][i].getUConst());
2459 break;
2460 default:
2461 UNREACHABLE();
2462 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302463 }
2464 }
Olli Etuahof119a262016-08-19 15:54:22 +03002465 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302466 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302467
Olli Etuahoe1805592017-01-02 16:41:20 +00002468 case EOpLessThanEqualComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302469 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002470 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302471 for (size_t i = 0; i < maxObjectSize; i++)
2472 {
2473 switch (basicType)
2474 {
Olli Etuahof119a262016-08-19 15:54:22 +03002475 case EbtFloat:
2476 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2477 unionArrays[1][i].getFConst());
2478 break;
2479 case EbtInt:
2480 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2481 unionArrays[1][i].getIConst());
2482 break;
2483 case EbtUInt:
2484 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2485 unionArrays[1][i].getUConst());
2486 break;
2487 default:
2488 UNREACHABLE();
2489 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302490 }
2491 }
Olli Etuahof119a262016-08-19 15:54:22 +03002492 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302493 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302494
Olli Etuahoe1805592017-01-02 16:41:20 +00002495 case EOpGreaterThanComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302496 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002497 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302498 for (size_t i = 0; i < maxObjectSize; i++)
2499 {
2500 switch (basicType)
2501 {
Olli Etuahof119a262016-08-19 15:54:22 +03002502 case EbtFloat:
2503 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2504 unionArrays[1][i].getFConst());
2505 break;
2506 case EbtInt:
2507 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2508 unionArrays[1][i].getIConst());
2509 break;
2510 case EbtUInt:
2511 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2512 unionArrays[1][i].getUConst());
2513 break;
2514 default:
2515 UNREACHABLE();
2516 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002517 }
2518 }
Olli Etuahof119a262016-08-19 15:54:22 +03002519 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302520 }
Olli Etuahoe1805592017-01-02 16:41:20 +00002521 case EOpGreaterThanEqualComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302522 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002523 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302524 for (size_t i = 0; i < maxObjectSize; i++)
2525 {
2526 switch (basicType)
2527 {
Olli Etuahof119a262016-08-19 15:54:22 +03002528 case EbtFloat:
2529 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2530 unionArrays[1][i].getFConst());
2531 break;
2532 case EbtInt:
2533 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2534 unionArrays[1][i].getIConst());
2535 break;
2536 case EbtUInt:
2537 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2538 unionArrays[1][i].getUConst());
2539 break;
2540 default:
2541 UNREACHABLE();
2542 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302543 }
2544 }
2545 }
2546 break;
2547
Olli Etuahoe1805592017-01-02 16:41:20 +00002548 case EOpEqualComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302549 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002550 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302551 for (size_t i = 0; i < maxObjectSize; i++)
2552 {
2553 switch (basicType)
2554 {
Olli Etuahof119a262016-08-19 15:54:22 +03002555 case EbtFloat:
2556 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2557 unionArrays[1][i].getFConst());
2558 break;
2559 case EbtInt:
2560 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2561 unionArrays[1][i].getIConst());
2562 break;
2563 case EbtUInt:
2564 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2565 unionArrays[1][i].getUConst());
2566 break;
2567 case EbtBool:
2568 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2569 unionArrays[1][i].getBConst());
2570 break;
2571 default:
2572 UNREACHABLE();
2573 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302574 }
2575 }
Olli Etuahof119a262016-08-19 15:54:22 +03002576 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302577 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302578
Olli Etuahoe1805592017-01-02 16:41:20 +00002579 case EOpNotEqualComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302580 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002581 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302582 for (size_t i = 0; i < maxObjectSize; i++)
2583 {
2584 switch (basicType)
2585 {
Olli Etuahof119a262016-08-19 15:54:22 +03002586 case EbtFloat:
2587 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2588 unionArrays[1][i].getFConst());
2589 break;
2590 case EbtInt:
2591 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2592 unionArrays[1][i].getIConst());
2593 break;
2594 case EbtUInt:
2595 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2596 unionArrays[1][i].getUConst());
2597 break;
2598 case EbtBool:
2599 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2600 unionArrays[1][i].getBConst());
2601 break;
2602 default:
2603 UNREACHABLE();
2604 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302605 }
2606 }
Olli Etuahof119a262016-08-19 15:54:22 +03002607 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302608 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302609
Olli Etuahof119a262016-08-19 15:54:22 +03002610 case EOpDistance:
Arun Patole1155ddd2015-06-05 18:04:36 +05302611 {
Olli Etuahof119a262016-08-19 15:54:22 +03002612 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302613 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002614 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302615 for (size_t i = 0; i < maxObjectSize; i++)
2616 {
2617 float x = unionArrays[0][i].getFConst();
2618 float y = unionArrays[1][i].getFConst();
2619 distanceArray[i].setFConst(x - y);
2620 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002621 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Olli Etuahof119a262016-08-19 15:54:22 +03002622 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302623 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302624
Olli Etuahof119a262016-08-19 15:54:22 +03002625 case EOpDot:
2626 ASSERT(basicType == EbtFloat);
Olli Etuahob43846e2015-06-02 18:18:57 +03002627 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002628 resultArray->setFConst(
2629 VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2630 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302631
Olli Etuahof119a262016-08-19 15:54:22 +03002632 case EOpCross:
Arun Patole1155ddd2015-06-05 18:04:36 +05302633 {
Olli Etuahof119a262016-08-19 15:54:22 +03002634 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
Olli Etuahob43846e2015-06-02 18:18:57 +03002635 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002636 float x0 = unionArrays[0][0].getFConst();
2637 float x1 = unionArrays[0][1].getFConst();
2638 float x2 = unionArrays[0][2].getFConst();
2639 float y0 = unionArrays[1][0].getFConst();
2640 float y1 = unionArrays[1][1].getFConst();
2641 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002642 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2643 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2644 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Olli Etuahof119a262016-08-19 15:54:22 +03002645 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302646 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302647
Olli Etuahof119a262016-08-19 15:54:22 +03002648 case EOpReflect:
Arun Patole1155ddd2015-06-05 18:04:36 +05302649 {
Olli Etuahof119a262016-08-19 15:54:22 +03002650 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302651 // genType reflect (genType I, genType N) :
Olli Etuahof119a262016-08-19 15:54:22 +03002652 // For the incident vector I and surface orientation N, returns the reflection
2653 // direction:
Arun Patole1155ddd2015-06-05 18:04:36 +05302654 // I - 2 * dot(N, I) * N.
Olli Etuahof119a262016-08-19 15:54:22 +03002655 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302656 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2657 for (size_t i = 0; i < maxObjectSize; i++)
2658 {
2659 float result = unionArrays[0][i].getFConst() -
2660 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002661 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302662 }
Olli Etuahof119a262016-08-19 15:54:22 +03002663 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302664 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302665
Olli Etuahoe1805592017-01-02 16:41:20 +00002666 case EOpMulMatrixComponentWise:
Arun Patole7fa33552015-06-10 15:15:18 +05302667 {
Olli Etuahof119a262016-08-19 15:54:22 +03002668 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2669 (*sequence)[1]->getAsTyped()->isMatrix());
Arun Patole7fa33552015-06-10 15:15:18 +05302670 // Perform component-wise matrix multiplication.
2671 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002672 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302673 angle::Matrix<float> result =
2674 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2675 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002676 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302677 }
Arun Patole7fa33552015-06-10 15:15:18 +05302678
Olli Etuahof119a262016-08-19 15:54:22 +03002679 case EOpOuterProduct:
Arun Patole7fa33552015-06-10 15:15:18 +05302680 {
Olli Etuahof119a262016-08-19 15:54:22 +03002681 ASSERT(basicType == EbtFloat);
Arun Patole7fa33552015-06-10 15:15:18 +05302682 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2683 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuahof119a262016-08-19 15:54:22 +03002684 resultArray = new TConstantUnion[numRows * numCols];
Arun Patole7fa33552015-06-10 15:15:18 +05302685 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002686 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2687 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302688 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002689 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302690 }
Arun Patole7fa33552015-06-10 15:15:18 +05302691
Olli Etuahof119a262016-08-19 15:54:22 +03002692 default:
2693 UNREACHABLE();
2694 // TODO: Add constant folding support for other built-in operations that take 2
2695 // parameters and not handled above.
2696 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302697 }
2698 }
2699 else if (paramsCount == 3)
2700 {
2701 //
2702 // Ternary built-in
2703 //
2704 switch (op)
2705 {
Olli Etuahof119a262016-08-19 15:54:22 +03002706 case EOpClamp:
Arun Patole274f0702015-05-05 13:33:30 +05302707 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002708 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302709 for (size_t i = 0; i < maxObjectSize; i++)
2710 {
2711 switch (basicType)
2712 {
Olli Etuahof119a262016-08-19 15:54:22 +03002713 case EbtFloat:
Arun Patole274f0702015-05-05 13:33:30 +05302714 {
Olli Etuahof119a262016-08-19 15:54:22 +03002715 float x = unionArrays[0][i].getFConst();
Arun Patole274f0702015-05-05 13:33:30 +05302716 float min = unionArrays[1][i].getFConst();
2717 float max = unionArrays[2][i].getFConst();
2718 // Results are undefined if min > max.
2719 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002720 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2721 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302722 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002723 resultArray[i].setFConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002724 break;
Arun Patole274f0702015-05-05 13:33:30 +05302725 }
Olli Etuahof119a262016-08-19 15:54:22 +03002726
2727 case EbtInt:
Arun Patole274f0702015-05-05 13:33:30 +05302728 {
Olli Etuahof119a262016-08-19 15:54:22 +03002729 int x = unionArrays[0][i].getIConst();
Arun Patole274f0702015-05-05 13:33:30 +05302730 int min = unionArrays[1][i].getIConst();
2731 int max = unionArrays[2][i].getIConst();
2732 // Results are undefined if min > max.
2733 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002734 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2735 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302736 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002737 resultArray[i].setIConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002738 break;
Arun Patole274f0702015-05-05 13:33:30 +05302739 }
Olli Etuahof119a262016-08-19 15:54:22 +03002740 case EbtUInt:
Arun Patole274f0702015-05-05 13:33:30 +05302741 {
Olli Etuahof119a262016-08-19 15:54:22 +03002742 unsigned int x = unionArrays[0][i].getUConst();
Arun Patole274f0702015-05-05 13:33:30 +05302743 unsigned int min = unionArrays[1][i].getUConst();
2744 unsigned int max = unionArrays[2][i].getUConst();
2745 // Results are undefined if min > max.
2746 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002747 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2748 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302749 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002750 resultArray[i].setUConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002751 break;
Arun Patole274f0702015-05-05 13:33:30 +05302752 }
Olli Etuahof119a262016-08-19 15:54:22 +03002753 default:
2754 UNREACHABLE();
2755 break;
Arun Patole274f0702015-05-05 13:33:30 +05302756 }
2757 }
Olli Etuahof119a262016-08-19 15:54:22 +03002758 break;
Arun Patole274f0702015-05-05 13:33:30 +05302759 }
Arun Patole274f0702015-05-05 13:33:30 +05302760
Olli Etuahof119a262016-08-19 15:54:22 +03002761 case EOpMix:
Arun Patolebf790422015-05-18 17:53:04 +05302762 {
Olli Etuahof119a262016-08-19 15:54:22 +03002763 ASSERT(basicType == EbtFloat);
2764 resultArray = new TConstantUnion[maxObjectSize];
2765 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302766 {
Olli Etuahof119a262016-08-19 15:54:22 +03002767 float x = unionArrays[0][i].getFConst();
2768 float y = unionArrays[1][i].getFConst();
2769 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2770 if (type == EbtFloat)
Arun Patolebf790422015-05-18 17:53:04 +05302771 {
Olli Etuahof119a262016-08-19 15:54:22 +03002772 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2773 float a = unionArrays[2][i].getFConst();
2774 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2775 }
2776 else // 3rd parameter is EbtBool
2777 {
2778 ASSERT(type == EbtBool);
2779 // Selects which vector each returned component comes from.
2780 // For a component of a that is false, the corresponding component of x is
2781 // returned.
2782 // For a component of a that is true, the corresponding component of y is
2783 // returned.
2784 bool a = unionArrays[2][i].getBConst();
2785 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302786 }
2787 }
Olli Etuahof119a262016-08-19 15:54:22 +03002788 break;
Arun Patolebf790422015-05-18 17:53:04 +05302789 }
Arun Patolebf790422015-05-18 17:53:04 +05302790
Olli Etuahof119a262016-08-19 15:54:22 +03002791 case EOpSmoothStep:
Arun Patolebf790422015-05-18 17:53:04 +05302792 {
Olli Etuahof119a262016-08-19 15:54:22 +03002793 ASSERT(basicType == EbtFloat);
2794 resultArray = new TConstantUnion[maxObjectSize];
2795 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302796 {
Olli Etuahof119a262016-08-19 15:54:22 +03002797 float edge0 = unionArrays[0][i].getFConst();
2798 float edge1 = unionArrays[1][i].getFConst();
2799 float x = unionArrays[2][i].getFConst();
2800 // Results are undefined if edge0 >= edge1.
2801 if (edge0 >= edge1)
Arun Patolebf790422015-05-18 17:53:04 +05302802 {
Olli Etuahof119a262016-08-19 15:54:22 +03002803 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2804 &resultArray[i]);
2805 }
2806 else
2807 {
2808 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2809 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2810 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2811 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302812 }
2813 }
Olli Etuahof119a262016-08-19 15:54:22 +03002814 break;
Arun Patolebf790422015-05-18 17:53:04 +05302815 }
Arun Patolebf790422015-05-18 17:53:04 +05302816
Olli Etuahof119a262016-08-19 15:54:22 +03002817 case EOpFaceForward:
Arun Patole1155ddd2015-06-05 18:04:36 +05302818 {
Olli Etuahof119a262016-08-19 15:54:22 +03002819 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302820 // genType faceforward(genType N, genType I, genType Nref) :
2821 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahof119a262016-08-19 15:54:22 +03002822 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302823 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2824 for (size_t i = 0; i < maxObjectSize; i++)
2825 {
2826 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002827 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302828 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002829 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302830 }
Olli Etuahof119a262016-08-19 15:54:22 +03002831 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302832 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302833
Olli Etuahof119a262016-08-19 15:54:22 +03002834 case EOpRefract:
Arun Patole1155ddd2015-06-05 18:04:36 +05302835 {
Olli Etuahof119a262016-08-19 15:54:22 +03002836 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302837 // genType refract(genType I, genType N, float eta) :
Olli Etuahof119a262016-08-19 15:54:22 +03002838 // For the incident vector I and surface normal N, and the ratio of indices of
2839 // refraction eta,
Arun Patole1155ddd2015-06-05 18:04:36 +05302840 // return the refraction vector. The result is computed by
2841 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2842 // if (k < 0.0)
2843 // return genType(0.0)
2844 // else
2845 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahof119a262016-08-19 15:54:22 +03002846 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302847 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2848 for (size_t i = 0; i < maxObjectSize; i++)
2849 {
2850 float eta = unionArrays[2][i].getFConst();
Olli Etuahof119a262016-08-19 15:54:22 +03002851 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
Arun Patole1155ddd2015-06-05 18:04:36 +05302852 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002853 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302854 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002855 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Olli Etuahof119a262016-08-19 15:54:22 +03002856 (eta * dotProduct + sqrtf(k)) *
2857 unionArrays[1][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302858 }
Olli Etuahof119a262016-08-19 15:54:22 +03002859 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302860 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302861
Olli Etuahof119a262016-08-19 15:54:22 +03002862 default:
2863 UNREACHABLE();
2864 // TODO: Add constant folding support for other built-in operations that take 3
2865 // parameters and not handled above.
2866 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302867 }
2868 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002869 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302870}
2871
2872// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002873TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2874{
2875 if (hashFunction == NULL || name.empty())
2876 return name;
2877 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2878 TStringStream stream;
2879 stream << HASHED_NAME_PREFIX << std::hex << number;
2880 TString hashedName = stream.str();
2881 return hashedName;
2882}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002883
2884void TIntermTraverser::updateTree()
2885{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002886 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2887 {
2888 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2889 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002890 if (!insertion.insertionsAfter.empty())
2891 {
2892 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2893 insertion.insertionsAfter);
2894 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002895 }
2896 if (!insertion.insertionsBefore.empty())
2897 {
2898 bool inserted =
2899 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2900 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002901 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002902 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002903 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2904 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002905 const NodeUpdateEntry &replacement = mReplacements[ii];
2906 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002907 bool replaced =
2908 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002909 ASSERT(replaced);
2910
Olli Etuahocd94ef92015-04-16 19:18:10 +03002911 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002912 {
2913 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002914 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002915 // be replaced, we need to make sure we don't update the replaced
2916 // node; instead, we update the replacement node.
2917 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2918 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002919 NodeUpdateEntry &replacement2 = mReplacements[jj];
2920 if (replacement2.parent == replacement.original)
2921 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002922 }
2923 }
2924 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002925 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2926 {
2927 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2928 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002929 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
2930 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002931 ASSERT(replaced);
2932 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002933
Jamie Madill03d863c2016-07-27 18:15:53 -04002934 clearReplacementQueue();
2935}
2936
2937void TIntermTraverser::clearReplacementQueue()
2938{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002939 mReplacements.clear();
2940 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002941 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002942}
Jamie Madill1048e432016-07-23 18:51:28 -04002943
Jamie Madill03d863c2016-07-27 18:15:53 -04002944void TIntermTraverser::queueReplacement(TIntermNode *original,
2945 TIntermNode *replacement,
2946 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002947{
Jamie Madill03d863c2016-07-27 18:15:53 -04002948 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002949}
2950
Jamie Madill03d863c2016-07-27 18:15:53 -04002951void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2952 TIntermNode *original,
2953 TIntermNode *replacement,
2954 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002955{
Jamie Madill03d863c2016-07-27 18:15:53 -04002956 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2957 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002958}
Jamie Madill45bcc782016-11-07 13:58:48 -05002959
2960} // namespace sh