blob: 61fcb40642a52eda47aa62c371bde40aa9b089a3 [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{
214 REPLACE_IF_IS(mParameters, TIntermAggregate, original, replacement);
215 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 Etuaho13389b62016-10-16 11:48:18 +0100229bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
230{
231 return replaceChildNodeInternal(original, replacement);
232}
233
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100234bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
235{
236 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400237 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100238 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400239 }
240 return false;
241}
242
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100243bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
244 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300245{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100246 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300247 {
248 if (*it == original)
249 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100250 it = getSequence()->erase(it);
251 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300252 return true;
253 }
254 }
255 return false;
256}
257
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100258bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
259 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300260{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100261 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300262 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300263 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300264 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100265 auto it = getSequence()->begin() + position;
266 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300267 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300268}
269
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200270bool TIntermAggregate::areChildrenConstQualified()
271{
272 for (TIntermNode *&child : mSequence)
273 {
274 TIntermTyped *typed = child->getAsTyped();
275 if (typed && typed->getQualifier() != EvqConst)
276 {
277 return false;
278 }
279 }
280 return true;
281}
282
Olli Etuahod2a67b92014-10-21 16:42:57 +0300283void TIntermAggregate::setPrecisionFromChildren()
284{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300285 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300286 if (getBasicType() == EbtBool)
287 {
288 mType.setPrecision(EbpUndefined);
289 return;
290 }
291
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500292 TPrecision precision = EbpUndefined;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300293 TIntermSequence::iterator childIter = mSequence.begin();
294 while (childIter != mSequence.end())
295 {
296 TIntermTyped *typed = (*childIter)->getAsTyped();
297 if (typed)
298 precision = GetHigherPrecision(typed->getPrecision(), precision);
299 ++childIter;
300 }
301 mType.setPrecision(precision);
302}
303
304void TIntermAggregate::setBuiltInFunctionPrecision()
305{
306 // All built-ins returning bool should be handled as ops, not functions.
307 ASSERT(getBasicType() != EbtBool);
308
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500309 TPrecision precision = EbpUndefined;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300310 TIntermSequence::iterator childIter = mSequence.begin();
311 while (childIter != mSequence.end())
312 {
313 TIntermTyped *typed = (*childIter)->getAsTyped();
314 // ESSL spec section 8: texture functions get their precision from the sampler.
315 if (typed && IsSampler(typed->getBasicType()))
316 {
317 precision = typed->getPrecision();
318 break;
319 }
320 ++childIter;
321 }
322 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
323 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100324 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300325 mType.setPrecision(EbpHigh);
326 else
327 mType.setPrecision(precision);
328}
329
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100330void TIntermBlock::appendStatement(TIntermNode *statement)
331{
Olli Etuaho13389b62016-10-16 11:48:18 +0100332 // Declaration nodes with no children can appear if all the declarators just added constants to
333 // the symbol table instead of generating code. They're no-ops so they aren't added to blocks.
334 if (statement != nullptr && (statement->getAsDeclarationNode() == nullptr ||
335 !statement->getAsDeclarationNode()->getSequence()->empty()))
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100336 {
337 mStatements.push_back(statement);
338 }
339}
340
Olli Etuaho13389b62016-10-16 11:48:18 +0100341void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
342{
343 ASSERT(declarator != nullptr);
344 ASSERT(declarator->getAsSymbolNode() != nullptr ||
345 (declarator->getAsBinaryNode() != nullptr &&
346 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
347 ASSERT(mDeclarators.empty() ||
348 declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType()));
349 mDeclarators.push_back(declarator);
350}
351
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300352bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
353{
354 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
355 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
356 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
357 return false;
358}
359
Olli Etuaho57961272016-09-14 13:57:46 +0300360bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400361{
362 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100363 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
364 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400365 return false;
366}
367
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500368bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200369{
370 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100371 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200372 return false;
373}
374
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500375bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200376{
377 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
378 return false;
379}
380
Olli Etuahod7a25242015-08-18 13:49:45 +0300381TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
382{
383 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
384 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
385 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
386 mLine = node.mLine;
387}
388
Olli Etuahod4f4c112016-04-15 15:11:24 +0300389bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
390{
391 TIntermAggregate *constructor = getAsAggregate();
392 if (!constructor || !constructor->isConstructor())
393 {
394 return false;
395 }
396 for (TIntermNode *&node : *constructor->getSequence())
397 {
398 if (!node->getAsConstantUnion())
399 return false;
400 }
401 return true;
402}
403
Corentin Wallez509e4562016-08-25 14:55:44 -0400404// static
405TIntermTyped *TIntermTyped::CreateIndexNode(int index)
406{
407 TConstantUnion *u = new TConstantUnion[1];
408 u[0].setIConst(index);
409
410 TType type(EbtInt, EbpUndefined, EvqConst, 1);
411 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
412 return node;
413}
414
415// static
416TIntermTyped *TIntermTyped::CreateZero(const TType &type)
417{
418 TType constType(type);
419 constType.setQualifier(EvqConst);
420
421 if (!type.isArray() && type.getBasicType() != EbtStruct)
422 {
423 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
424
425 size_t size = constType.getObjectSize();
426 TConstantUnion *u = new TConstantUnion[size];
427 for (size_t i = 0; i < size; ++i)
428 {
429 switch (type.getBasicType())
430 {
431 case EbtFloat:
432 u[i].setFConst(0.0f);
433 break;
434 case EbtInt:
435 u[i].setIConst(0);
436 break;
437 case EbtUInt:
438 u[i].setUConst(0u);
439 break;
440 case EbtBool:
441 u[i].setBConst(false);
442 break;
443 default:
444 UNREACHABLE();
445 return nullptr;
446 }
447 }
448
449 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
450 return node;
451 }
452
453 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
454 constructor->setType(constType);
455
456 if (type.isArray())
457 {
458 TType elementType(type);
459 elementType.clearArrayness();
460
461 size_t arraySize = type.getArraySize();
462 for (size_t i = 0; i < arraySize; ++i)
463 {
464 constructor->getSequence()->push_back(CreateZero(elementType));
465 }
466 }
467 else
468 {
469 ASSERT(type.getBasicType() == EbtStruct);
470
471 TStructure *structure = type.getStruct();
472 for (const auto &field : structure->fields())
473 {
474 constructor->getSequence()->push_back(CreateZero(*field->type()));
475 }
476 }
477
478 return constructor;
479}
480
Corentin Wallez36fd1002016-12-08 11:30:44 -0500481// static
482TIntermTyped *TIntermTyped::CreateBool(bool value)
483{
484 TConstantUnion *u = new TConstantUnion[1];
485 u[0].setBConst(value);
486
487 TType type(EbtBool, EbpUndefined, EvqConst, 1);
488 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
489 return node;
490}
491
Olli Etuahod7a25242015-08-18 13:49:45 +0300492TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
493{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200494 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300495}
496
Olli Etuahobd674552016-10-06 13:28:42 +0100497void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
498{
499 setName(function.getMangledName());
500 setId(function.getUniqueId());
501}
502
Olli Etuahod7a25242015-08-18 13:49:45 +0300503TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
504 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300505 mUserDefined(node.mUserDefined),
Olli Etuahod7a25242015-08-18 13:49:45 +0300506 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100507 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
508 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300509{
510 for (TIntermNode *child : node.mSequence)
511 {
512 TIntermTyped *typedChild = child->getAsTyped();
513 ASSERT(typedChild != nullptr);
514 TIntermTyped *childCopy = typedChild->deepCopy();
515 mSequence.push_back(childCopy);
516 }
517}
518
Olli Etuahob6fa0432016-09-28 16:28:05 +0100519TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
520{
521 TIntermTyped *operandCopy = node.mOperand->deepCopy();
522 ASSERT(operandCopy != nullptr);
523 mOperand = operandCopy;
524}
525
Olli Etuahod7a25242015-08-18 13:49:45 +0300526TIntermBinary::TIntermBinary(const TIntermBinary &node)
527 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
528{
529 TIntermTyped *leftCopy = node.mLeft->deepCopy();
530 TIntermTyped *rightCopy = node.mRight->deepCopy();
531 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
532 mLeft = leftCopy;
533 mRight = rightCopy;
534}
535
536TIntermUnary::TIntermUnary(const TIntermUnary &node)
537 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
538{
539 TIntermTyped *operandCopy = node.mOperand->deepCopy();
540 ASSERT(operandCopy != nullptr);
541 mOperand = operandCopy;
542}
543
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300544TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300545{
Olli Etuahod7a25242015-08-18 13:49:45 +0300546 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300547 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
548 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300549 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300550 mCondition = conditionCopy;
551 mTrueExpression = trueCopy;
552 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300553}
554
Jamie Madillb1a85f42014-08-19 15:23:24 -0400555bool TIntermOperator::isAssignment() const
556{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300557 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400558}
559
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300560bool TIntermOperator::isMultiplication() const
561{
562 switch (mOp)
563 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500564 case EOpMul:
565 case EOpMatrixTimesMatrix:
566 case EOpMatrixTimesVector:
567 case EOpMatrixTimesScalar:
568 case EOpVectorTimesMatrix:
569 case EOpVectorTimesScalar:
570 return true;
571 default:
572 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300573 }
574}
575
Jamie Madillb1a85f42014-08-19 15:23:24 -0400576//
577// returns true if the operator is for one of the constructors
578//
579bool TIntermOperator::isConstructor() const
580{
581 switch (mOp)
582 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500583 case EOpConstructVec2:
584 case EOpConstructVec3:
585 case EOpConstructVec4:
586 case EOpConstructMat2:
587 case EOpConstructMat2x3:
588 case EOpConstructMat2x4:
589 case EOpConstructMat3x2:
590 case EOpConstructMat3:
591 case EOpConstructMat3x4:
592 case EOpConstructMat4x2:
593 case EOpConstructMat4x3:
594 case EOpConstructMat4:
595 case EOpConstructFloat:
596 case EOpConstructIVec2:
597 case EOpConstructIVec3:
598 case EOpConstructIVec4:
599 case EOpConstructInt:
600 case EOpConstructUVec2:
601 case EOpConstructUVec3:
602 case EOpConstructUVec4:
603 case EOpConstructUInt:
604 case EOpConstructBVec2:
605 case EOpConstructBVec3:
606 case EOpConstructBVec4:
607 case EOpConstructBool:
608 case EOpConstructStruct:
609 return true;
610 default:
611 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400612 }
613}
614
Olli Etuaho1dded802016-08-18 18:13:13 +0300615TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
616{
617 if (left.isMatrix())
618 {
619 if (right.isMatrix())
620 {
621 return EOpMatrixTimesMatrix;
622 }
623 else
624 {
625 if (right.isVector())
626 {
627 return EOpMatrixTimesVector;
628 }
629 else
630 {
631 return EOpMatrixTimesScalar;
632 }
633 }
634 }
635 else
636 {
637 if (right.isMatrix())
638 {
639 if (left.isVector())
640 {
641 return EOpVectorTimesMatrix;
642 }
643 else
644 {
645 return EOpMatrixTimesScalar;
646 }
647 }
648 else
649 {
650 // Neither operand is a matrix.
651 if (left.isVector() == right.isVector())
652 {
653 // Leave as component product.
654 return EOpMul;
655 }
656 else
657 {
658 return EOpVectorTimesScalar;
659 }
660 }
661 }
662}
663
664TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
665{
666 if (left.isMatrix())
667 {
668 if (right.isMatrix())
669 {
670 return EOpMatrixTimesMatrixAssign;
671 }
672 else
673 {
674 // right should be scalar, but this may not be validated yet.
675 return EOpMatrixTimesScalarAssign;
676 }
677 }
678 else
679 {
680 if (right.isMatrix())
681 {
682 // Left should be a vector, but this may not be validated yet.
683 return EOpVectorTimesMatrixAssign;
684 }
685 else
686 {
687 // Neither operand is a matrix.
688 if (left.isVector() == right.isVector())
689 {
690 // Leave as component product.
691 return EOpMulAssign;
692 }
693 else
694 {
695 // left should be vector and right should be scalar, but this may not be validated
696 // yet.
697 return EOpVectorTimesScalarAssign;
698 }
699 }
700 }
701}
702
Jamie Madillb1a85f42014-08-19 15:23:24 -0400703//
704// Make sure the type of a unary operator is appropriate for its
705// combination of operation and operand type.
706//
Olli Etuahoa2234302016-08-31 12:05:39 +0300707void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400708{
Olli Etuahoa2234302016-08-31 12:05:39 +0300709 TQualifier resultQualifier = EvqTemporary;
710 if (mOperand->getQualifier() == EvqConst)
711 resultQualifier = EvqConst;
712
713 unsigned char operandPrimarySize =
714 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400715 switch (mOp)
716 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300717 case EOpFloatBitsToInt:
718 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
719 break;
720 case EOpFloatBitsToUint:
721 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
722 break;
723 case EOpIntBitsToFloat:
724 case EOpUintBitsToFloat:
725 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
726 break;
727 case EOpPackSnorm2x16:
728 case EOpPackUnorm2x16:
729 case EOpPackHalf2x16:
730 setType(TType(EbtUInt, EbpHigh, resultQualifier));
731 break;
732 case EOpUnpackSnorm2x16:
733 case EOpUnpackUnorm2x16:
734 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
735 break;
736 case EOpUnpackHalf2x16:
737 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
738 break;
739 case EOpAny:
740 case EOpAll:
741 setType(TType(EbtBool, EbpUndefined, resultQualifier));
742 break;
743 case EOpLength:
744 case EOpDeterminant:
745 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
746 break;
747 case EOpTranspose:
748 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
749 static_cast<unsigned char>(mOperand->getType().getRows()),
750 static_cast<unsigned char>(mOperand->getType().getCols())));
751 break;
752 case EOpIsInf:
753 case EOpIsNan:
754 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
755 break;
756 default:
757 setType(mOperand->getType());
758 mType.setQualifier(resultQualifier);
759 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400760 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300761}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400762
Olli Etuahob6fa0432016-09-28 16:28:05 +0100763TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
764 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
765 mOperand(operand),
766 mSwizzleOffsets(swizzleOffsets)
767{
768 ASSERT(mSwizzleOffsets.size() <= 4);
769 promote();
770}
771
Olli Etuahoa2234302016-08-31 12:05:39 +0300772TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
773 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
774{
775 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400776}
777
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300778TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
779 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
780{
781 promote();
782}
783
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000784TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
785 : TIntermNode(), mSymbol(symbol)
786{
787 ASSERT(symbol);
788 setLine(line);
789}
790
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300791TIntermTernary::TIntermTernary(TIntermTyped *cond,
792 TIntermTyped *trueExpression,
793 TIntermTyped *falseExpression)
794 : TIntermTyped(trueExpression->getType()),
795 mCondition(cond),
796 mTrueExpression(trueExpression),
797 mFalseExpression(falseExpression)
798{
799 getTypePointer()->setQualifier(
800 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
801}
802
803// static
804TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
805 TIntermTyped *trueExpression,
806 TIntermTyped *falseExpression)
807{
808 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
809 falseExpression->getQualifier() == EvqConst)
810 {
811 return EvqConst;
812 }
813 return EvqTemporary;
814}
815
Olli Etuahob6fa0432016-09-28 16:28:05 +0100816void TIntermSwizzle::promote()
817{
818 TQualifier resultQualifier = EvqTemporary;
819 if (mOperand->getQualifier() == EvqConst)
820 resultQualifier = EvqConst;
821
822 auto numFields = mSwizzleOffsets.size();
823 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
824 static_cast<unsigned char>(numFields)));
825}
826
827bool TIntermSwizzle::hasDuplicateOffsets() const
828{
829 int offsetCount[4] = {0u, 0u, 0u, 0u};
830 for (const auto offset : mSwizzleOffsets)
831 {
832 offsetCount[offset]++;
833 if (offsetCount[offset] > 1)
834 {
835 return true;
836 }
837 }
838 return false;
839}
840
Olli Etuaho09b04a22016-12-15 13:30:26 +0000841bool TIntermSwizzle::offsetsMatch(int offset) const
842{
843 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
844}
845
Olli Etuahob6fa0432016-09-28 16:28:05 +0100846void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
847{
848 for (const int offset : mSwizzleOffsets)
849 {
850 switch (offset)
851 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500852 case 0:
853 *out << "x";
854 break;
855 case 1:
856 *out << "y";
857 break;
858 case 2:
859 *out << "z";
860 break;
861 case 3:
862 *out << "w";
863 break;
864 default:
865 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +0100866 }
867 }
868}
869
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100870TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
871 const TIntermTyped *left,
872 const TIntermTyped *right)
873{
874 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
875 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
876 right->getQualifier() != EvqConst)
877 {
878 return EvqTemporary;
879 }
880 return EvqConst;
881}
Olli Etuahob6fa0432016-09-28 16:28:05 +0100882
883// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300884void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400885{
Olli Etuaho1dded802016-08-18 18:13:13 +0300886 ASSERT(!isMultiplication() ||
887 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
888
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100889 // Comma is handled as a special case.
890 if (mOp == EOpComma)
891 {
892 setType(mRight->getType());
893 return;
894 }
895
Jamie Madillb1a85f42014-08-19 15:23:24 -0400896 // Base assumption: just make the type the same as the left
897 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400898 setType(mLeft->getType());
899
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200900 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400901 // Binary operations results in temporary variables unless both
902 // operands are const.
903 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
904 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200905 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400906 getTypePointer()->setQualifier(EvqTemporary);
907 }
908
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300909 // Handle indexing ops.
910 switch (mOp)
911 {
912 case EOpIndexDirect:
913 case EOpIndexIndirect:
914 if (mLeft->isArray())
915 {
916 mType.clearArrayness();
917 }
918 else if (mLeft->isMatrix())
919 {
920 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
921 static_cast<unsigned char>(mLeft->getRows())));
922 }
923 else if (mLeft->isVector())
924 {
925 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
926 }
927 else
928 {
929 UNREACHABLE();
930 }
931 return;
932 case EOpIndexDirectStruct:
933 {
934 const TFieldList &fields = mLeft->getType().getStruct()->fields();
935 const int i = mRight->getAsConstantUnion()->getIConst(0);
936 setType(*fields[i]->type());
937 getTypePointer()->setQualifier(resultQualifier);
938 return;
939 }
940 case EOpIndexDirectInterfaceBlock:
941 {
942 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
943 const int i = mRight->getAsConstantUnion()->getIConst(0);
944 setType(*fields[i]->type());
945 getTypePointer()->setQualifier(resultQualifier);
946 return;
947 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300948 default:
949 break;
950 }
951
952 ASSERT(mLeft->isArray() == mRight->isArray());
953
954 // The result gets promoted to the highest precision.
955 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
956 getTypePointer()->setPrecision(higherPrecision);
957
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500958 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400959
960 //
961 // All scalars or structs. Code after this test assumes this case is removed!
962 //
963 if (nominalSize == 1)
964 {
965 switch (mOp)
966 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500967 //
968 // Promote to conditional
969 //
970 case EOpEqual:
971 case EOpNotEqual:
972 case EOpLessThan:
973 case EOpGreaterThan:
974 case EOpLessThanEqual:
975 case EOpGreaterThanEqual:
976 setType(TType(EbtBool, EbpUndefined, resultQualifier));
977 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400978
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500979 //
980 // And and Or operate on conditionals
981 //
982 case EOpLogicalAnd:
983 case EOpLogicalXor:
984 case EOpLogicalOr:
985 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
986 setType(TType(EbtBool, EbpUndefined, resultQualifier));
987 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400988
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500989 default:
990 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400991 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300992 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400993 }
994
995 // If we reach here, at least one of the operands is vector or matrix.
996 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400997 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300998
Jamie Madillb1a85f42014-08-19 15:23:24 -0400999 switch (mOp)
1000 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001001 case EOpMul:
1002 break;
1003 case EOpMatrixTimesScalar:
1004 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001005 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001006 setType(TType(basicType, higherPrecision, resultQualifier,
1007 static_cast<unsigned char>(mRight->getCols()),
1008 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001009 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001010 break;
1011 case EOpMatrixTimesVector:
1012 setType(TType(basicType, higherPrecision, resultQualifier,
1013 static_cast<unsigned char>(mLeft->getRows()), 1));
1014 break;
1015 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001016 setType(TType(basicType, higherPrecision, resultQualifier,
1017 static_cast<unsigned char>(mRight->getCols()),
1018 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001019 break;
1020 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001021 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001022 static_cast<unsigned char>(nominalSize), 1));
1023 break;
1024 case EOpVectorTimesMatrix:
1025 setType(TType(basicType, higherPrecision, resultQualifier,
1026 static_cast<unsigned char>(mRight->getCols()), 1));
1027 break;
1028 case EOpMulAssign:
1029 case EOpVectorTimesScalarAssign:
1030 case EOpVectorTimesMatrixAssign:
1031 case EOpMatrixTimesScalarAssign:
1032 case EOpMatrixTimesMatrixAssign:
1033 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1034 break;
1035 case EOpAssign:
1036 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001037 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1038 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1039 break;
1040 case EOpAdd:
1041 case EOpSub:
1042 case EOpDiv:
1043 case EOpIMod:
1044 case EOpBitShiftLeft:
1045 case EOpBitShiftRight:
1046 case EOpBitwiseAnd:
1047 case EOpBitwiseXor:
1048 case EOpBitwiseOr:
1049 case EOpAddAssign:
1050 case EOpSubAssign:
1051 case EOpDivAssign:
1052 case EOpIModAssign:
1053 case EOpBitShiftLeftAssign:
1054 case EOpBitShiftRightAssign:
1055 case EOpBitwiseAndAssign:
1056 case EOpBitwiseXorAssign:
1057 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001058 {
1059 const int secondarySize =
1060 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1061 setType(TType(basicType, higherPrecision, resultQualifier,
1062 static_cast<unsigned char>(nominalSize),
1063 static_cast<unsigned char>(secondarySize)));
1064 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001065 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001066 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001067 case EOpEqual:
1068 case EOpNotEqual:
1069 case EOpLessThan:
1070 case EOpGreaterThan:
1071 case EOpLessThanEqual:
1072 case EOpGreaterThanEqual:
1073 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1074 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001075 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001076 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001077
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001078 case EOpIndexDirect:
1079 case EOpIndexIndirect:
1080 case EOpIndexDirectInterfaceBlock:
1081 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001082 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001083 UNREACHABLE();
1084 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001085 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001086 UNREACHABLE();
1087 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001088 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001089}
1090
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001091const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001092{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001093 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001094 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001095 ASSERT(index < static_cast<int>(getType().getArraySize()));
1096 TType arrayElementType = getType();
1097 arrayElementType.clearArrayness();
1098 size_t arrayElementSize = arrayElementType.getObjectSize();
1099 return &mUnionArrayPointer[arrayElementSize * index];
1100 }
1101 else if (isMatrix())
1102 {
1103 ASSERT(index < getType().getCols());
1104 int size = getType().getRows();
1105 return &mUnionArrayPointer[size * index];
1106 }
1107 else if (isVector())
1108 {
1109 ASSERT(index < getType().getNominalSize());
1110 return &mUnionArrayPointer[index];
1111 }
1112 else
1113 {
1114 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001115 return nullptr;
1116 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001117}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001118
Olli Etuahob6fa0432016-09-28 16:28:05 +01001119TIntermTyped *TIntermSwizzle::fold()
1120{
1121 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1122 if (operandConstant == nullptr)
1123 {
1124 return nullptr;
1125 }
1126
1127 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1128 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1129 {
1130 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1131 }
1132 return CreateFoldedNode(constArray, this, mType.getQualifier());
1133}
1134
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001135TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1136{
1137 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1138 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1139 switch (mOp)
1140 {
1141 case EOpIndexDirect:
1142 {
1143 if (leftConstant == nullptr || rightConstant == nullptr)
1144 {
1145 return nullptr;
1146 }
1147 int index = rightConstant->getIConst(0);
1148
1149 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1150 return CreateFoldedNode(constArray, this, mType.getQualifier());
1151 }
1152 case EOpIndexDirectStruct:
1153 {
1154 if (leftConstant == nullptr || rightConstant == nullptr)
1155 {
1156 return nullptr;
1157 }
1158 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1159 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1160
1161 size_t previousFieldsSize = 0;
1162 for (size_t i = 0; i < index; ++i)
1163 {
1164 previousFieldsSize += fields[i]->type()->getObjectSize();
1165 }
1166
1167 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1168 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1169 }
1170 case EOpIndexIndirect:
1171 case EOpIndexDirectInterfaceBlock:
1172 // Can never be constant folded.
1173 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001174 default:
1175 {
1176 if (leftConstant == nullptr || rightConstant == nullptr)
1177 {
1178 return nullptr;
1179 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001180 TConstantUnion *constArray =
1181 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001182
1183 // Nodes may be constant folded without being qualified as constant.
1184 return CreateFoldedNode(constArray, this, mType.getQualifier());
1185 }
1186 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001187}
1188
Olli Etuahof119a262016-08-19 15:54:22 +03001189TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001190{
1191 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1192 if (operandConstant == nullptr)
1193 {
1194 return nullptr;
1195 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301196
1197 TConstantUnion *constArray = nullptr;
1198 switch (mOp)
1199 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001200 case EOpAny:
1201 case EOpAll:
1202 case EOpLength:
1203 case EOpTranspose:
1204 case EOpDeterminant:
1205 case EOpInverse:
1206 case EOpPackSnorm2x16:
1207 case EOpUnpackSnorm2x16:
1208 case EOpPackUnorm2x16:
1209 case EOpUnpackUnorm2x16:
1210 case EOpPackHalf2x16:
1211 case EOpUnpackHalf2x16:
1212 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1213 break;
1214 default:
1215 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1216 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301217 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001218
1219 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001220 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001221}
1222
Olli Etuahof119a262016-08-19 15:54:22 +03001223TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001224{
1225 // Make sure that all params are constant before actual constant folding.
1226 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001227 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001228 if (param->getAsConstantUnion() == nullptr)
1229 {
1230 return nullptr;
1231 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001232 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001233 TConstantUnion *constArray = nullptr;
1234 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001235 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001236 else
Olli Etuahof119a262016-08-19 15:54:22 +03001237 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001238
1239 // Nodes may be constant folded without being qualified as constant.
1240 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
1241 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +03001242}
1243
Jamie Madillb1a85f42014-08-19 15:23:24 -04001244//
1245// The fold functions see if an operation on a constant can be done in place,
1246// without generating run-time code.
1247//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001248// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001249//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001250TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1251 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001252 TDiagnostics *diagnostics,
1253 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001254{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001255 const TConstantUnion *leftArray = getUnionArrayPointer();
1256 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001257
Olli Etuahof119a262016-08-19 15:54:22 +03001258 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001259
1260 size_t objectSize = getType().getObjectSize();
1261
1262 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1263 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1264 {
1265 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1266 }
1267 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1268 {
1269 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001270 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001271 objectSize = rightNode->getType().getObjectSize();
1272 }
1273
1274 TConstantUnion *resultArray = nullptr;
1275
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001276 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001277 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001278 case EOpAdd:
1279 resultArray = new TConstantUnion[objectSize];
1280 for (size_t i = 0; i < objectSize; i++)
1281 resultArray[i] =
1282 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1283 break;
1284 case EOpSub:
1285 resultArray = new TConstantUnion[objectSize];
1286 for (size_t i = 0; i < objectSize; i++)
1287 resultArray[i] =
1288 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1289 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001290
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001291 case EOpMul:
1292 case EOpVectorTimesScalar:
1293 case EOpMatrixTimesScalar:
1294 resultArray = new TConstantUnion[objectSize];
1295 for (size_t i = 0; i < objectSize; i++)
1296 resultArray[i] =
1297 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1298 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001299
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001300 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001301 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001302 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001303 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001304
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001305 const int leftCols = getCols();
1306 const int leftRows = getRows();
1307 const int rightCols = rightNode->getType().getCols();
1308 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001309 const int resultCols = rightCols;
1310 const int resultRows = leftRows;
1311
1312 resultArray = new TConstantUnion[resultCols * resultRows];
1313 for (int row = 0; row < resultRows; row++)
1314 {
1315 for (int column = 0; column < resultCols; column++)
1316 {
1317 resultArray[resultRows * column + row].setFConst(0.0f);
1318 for (int i = 0; i < leftCols; i++)
1319 {
1320 resultArray[resultRows * column + row].setFConst(
1321 resultArray[resultRows * column + row].getFConst() +
1322 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001323 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001324 }
1325 }
1326 }
1327 }
1328 break;
1329
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001330 case EOpDiv:
1331 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001332 {
1333 resultArray = new TConstantUnion[objectSize];
1334 for (size_t i = 0; i < objectSize; i++)
1335 {
1336 switch (getType().getBasicType())
1337 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001338 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001339 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001340 ASSERT(op == EOpDiv);
1341 float dividend = leftArray[i].getFConst();
1342 float divisor = rightArray[i].getFConst();
1343 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001344 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001345 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001346 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001347 diagnostics->warning(
1348 getLine(),
1349 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001350 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001351 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001352 }
1353 else
1354 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001355 diagnostics->warning(getLine(),
1356 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001357 bool negativeResult =
1358 std::signbit(dividend) != std::signbit(divisor);
1359 resultArray[i].setFConst(
1360 negativeResult ? -std::numeric_limits<float>::infinity()
1361 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001362 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001363 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001364 else if (gl::isInf(dividend) && gl::isInf(divisor))
1365 {
1366 diagnostics->warning(getLine(),
1367 "Infinity divided by infinity during constant "
1368 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001369 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001370 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1371 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001372 else
1373 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001374 float result = dividend / divisor;
1375 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001376 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001377 diagnostics->warning(
1378 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001379 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001380 }
1381 resultArray[i].setFConst(result);
1382 }
1383 break;
1384 }
1385 case EbtInt:
1386 if (rightArray[i] == 0)
1387 {
1388 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001389 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001390 resultArray[i].setIConst(INT_MAX);
1391 }
1392 else
1393 {
1394 int lhs = leftArray[i].getIConst();
1395 int divisor = rightArray[i].getIConst();
1396 if (op == EOpDiv)
1397 {
1398 // Check for the special case where the minimum representable number
1399 // is
1400 // divided by -1. If left alone this leads to integer overflow in
1401 // C++.
1402 // ESSL 3.00.6 section 4.1.3 Integers:
1403 // "However, for the case where the minimum representable value is
1404 // divided by -1, it is allowed to return either the minimum
1405 // representable value or the maximum representable value."
1406 if (lhs == -0x7fffffff - 1 && divisor == -1)
1407 {
1408 resultArray[i].setIConst(0x7fffffff);
1409 }
1410 else
1411 {
1412 resultArray[i].setIConst(lhs / divisor);
1413 }
Olli Etuahod4453572016-09-27 13:21:46 +01001414 }
1415 else
1416 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001417 ASSERT(op == EOpIMod);
1418 if (lhs < 0 || divisor < 0)
1419 {
1420 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1421 // when
1422 // either one of the operands is negative.
1423 diagnostics->warning(getLine(),
1424 "Negative modulus operator operand "
1425 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001426 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001427 resultArray[i].setIConst(0);
1428 }
1429 else
1430 {
1431 resultArray[i].setIConst(lhs % divisor);
1432 }
Olli Etuahod4453572016-09-27 13:21:46 +01001433 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001434 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001435 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001436
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001437 case EbtUInt:
1438 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001439 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001440 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001441 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001442 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001443 }
1444 else
1445 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001446 if (op == EOpDiv)
1447 {
1448 resultArray[i].setUConst(leftArray[i].getUConst() /
1449 rightArray[i].getUConst());
1450 }
1451 else
1452 {
1453 ASSERT(op == EOpIMod);
1454 resultArray[i].setUConst(leftArray[i].getUConst() %
1455 rightArray[i].getUConst());
1456 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001457 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001458 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001459
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001460 default:
1461 UNREACHABLE();
1462 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001463 }
1464 }
1465 }
1466 break;
1467
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001468 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001469 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001470 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001471 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001472
1473 const int matrixCols = getCols();
1474 const int matrixRows = getRows();
1475
1476 resultArray = new TConstantUnion[matrixRows];
1477
1478 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1479 {
1480 resultArray[matrixRow].setFConst(0.0f);
1481 for (int col = 0; col < matrixCols; col++)
1482 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001483 resultArray[matrixRow].setFConst(
1484 resultArray[matrixRow].getFConst() +
1485 leftArray[col * matrixRows + matrixRow].getFConst() *
1486 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001487 }
1488 }
1489 }
1490 break;
1491
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001492 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001493 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001494 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001495 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001496
1497 const int matrixCols = rightNode->getType().getCols();
1498 const int matrixRows = rightNode->getType().getRows();
1499
1500 resultArray = new TConstantUnion[matrixCols];
1501
1502 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1503 {
1504 resultArray[matrixCol].setFConst(0.0f);
1505 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1506 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001507 resultArray[matrixCol].setFConst(
1508 resultArray[matrixCol].getFConst() +
1509 leftArray[matrixRow].getFConst() *
1510 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001511 }
1512 }
1513 }
1514 break;
1515
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001516 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001517 {
1518 resultArray = new TConstantUnion[objectSize];
1519 for (size_t i = 0; i < objectSize; i++)
1520 {
1521 resultArray[i] = leftArray[i] && rightArray[i];
1522 }
1523 }
1524 break;
1525
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001526 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001527 {
1528 resultArray = new TConstantUnion[objectSize];
1529 for (size_t i = 0; i < objectSize; i++)
1530 {
1531 resultArray[i] = leftArray[i] || rightArray[i];
1532 }
1533 }
1534 break;
1535
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001536 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001537 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001538 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001539 resultArray = new TConstantUnion[objectSize];
1540 for (size_t i = 0; i < objectSize; i++)
1541 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001542 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001543 }
1544 }
1545 break;
1546
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001547 case EOpBitwiseAnd:
1548 resultArray = new TConstantUnion[objectSize];
1549 for (size_t i = 0; i < objectSize; i++)
1550 resultArray[i] = leftArray[i] & rightArray[i];
1551 break;
1552 case EOpBitwiseXor:
1553 resultArray = new TConstantUnion[objectSize];
1554 for (size_t i = 0; i < objectSize; i++)
1555 resultArray[i] = leftArray[i] ^ rightArray[i];
1556 break;
1557 case EOpBitwiseOr:
1558 resultArray = new TConstantUnion[objectSize];
1559 for (size_t i = 0; i < objectSize; i++)
1560 resultArray[i] = leftArray[i] | rightArray[i];
1561 break;
1562 case EOpBitShiftLeft:
1563 resultArray = new TConstantUnion[objectSize];
1564 for (size_t i = 0; i < objectSize; i++)
1565 resultArray[i] =
1566 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1567 break;
1568 case EOpBitShiftRight:
1569 resultArray = new TConstantUnion[objectSize];
1570 for (size_t i = 0; i < objectSize; i++)
1571 resultArray[i] =
1572 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1573 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001574
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001575 case EOpLessThan:
1576 ASSERT(objectSize == 1);
1577 resultArray = new TConstantUnion[1];
1578 resultArray->setBConst(*leftArray < *rightArray);
1579 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001580
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001581 case EOpGreaterThan:
1582 ASSERT(objectSize == 1);
1583 resultArray = new TConstantUnion[1];
1584 resultArray->setBConst(*leftArray > *rightArray);
1585 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001586
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001587 case EOpLessThanEqual:
1588 ASSERT(objectSize == 1);
1589 resultArray = new TConstantUnion[1];
1590 resultArray->setBConst(!(*leftArray > *rightArray));
1591 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001592
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001593 case EOpGreaterThanEqual:
1594 ASSERT(objectSize == 1);
1595 resultArray = new TConstantUnion[1];
1596 resultArray->setBConst(!(*leftArray < *rightArray));
1597 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001598
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001599 case EOpEqual:
1600 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001601 {
1602 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001603 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001604 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001605 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001606 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001607 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001608 equal = false;
1609 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001610 }
1611 }
1612 if (op == EOpEqual)
1613 {
1614 resultArray->setBConst(equal);
1615 }
1616 else
1617 {
1618 resultArray->setBConst(!equal);
1619 }
1620 }
1621 break;
1622
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001623 default:
1624 UNREACHABLE();
1625 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001626 }
1627 return resultArray;
1628}
1629
Olli Etuahof119a262016-08-19 15:54:22 +03001630// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1631// code. Returns the constant value to keep using. Nullptr should not be returned.
1632TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001633{
Olli Etuahof119a262016-08-19 15:54:22 +03001634 // Do operations where the return type may have a different number of components compared to the
1635 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001636
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001637 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001638 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301639
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001640 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301641 TConstantUnion *resultArray = nullptr;
1642 switch (op)
1643 {
Olli Etuahof119a262016-08-19 15:54:22 +03001644 case EOpAny:
1645 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301646 resultArray = new TConstantUnion();
1647 resultArray->setBConst(false);
1648 for (size_t i = 0; i < objectSize; i++)
1649 {
1650 if (operandArray[i].getBConst())
1651 {
1652 resultArray->setBConst(true);
1653 break;
1654 }
1655 }
1656 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301657
Olli Etuahof119a262016-08-19 15:54:22 +03001658 case EOpAll:
1659 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301660 resultArray = new TConstantUnion();
1661 resultArray->setBConst(true);
1662 for (size_t i = 0; i < objectSize; i++)
1663 {
1664 if (!operandArray[i].getBConst())
1665 {
1666 resultArray->setBConst(false);
1667 break;
1668 }
1669 }
1670 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301671
Olli Etuahof119a262016-08-19 15:54:22 +03001672 case EOpLength:
1673 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301674 resultArray = new TConstantUnion();
1675 resultArray->setFConst(VectorLength(operandArray, objectSize));
1676 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301677
Olli Etuahof119a262016-08-19 15:54:22 +03001678 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301679 {
Olli Etuahof119a262016-08-19 15:54:22 +03001680 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301681 resultArray = new TConstantUnion[objectSize];
1682 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001683 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301684 SetUnionArrayFromMatrix(result, resultArray);
1685 break;
1686 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301687
Olli Etuahof119a262016-08-19 15:54:22 +03001688 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301689 {
Olli Etuahof119a262016-08-19 15:54:22 +03001690 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301691 unsigned int size = getType().getNominalSize();
1692 ASSERT(size >= 2 && size <= 4);
1693 resultArray = new TConstantUnion();
1694 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1695 break;
1696 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301697
Olli Etuahof119a262016-08-19 15:54:22 +03001698 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301699 {
Olli Etuahof119a262016-08-19 15:54:22 +03001700 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301701 unsigned int size = getType().getNominalSize();
1702 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001703 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301704 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1705 SetUnionArrayFromMatrix(result, resultArray);
1706 break;
1707 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301708
Olli Etuahof119a262016-08-19 15:54:22 +03001709 case EOpPackSnorm2x16:
1710 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301711 ASSERT(getType().getNominalSize() == 2);
1712 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001713 resultArray->setUConst(
1714 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301715 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301716
Olli Etuahof119a262016-08-19 15:54:22 +03001717 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301718 {
Olli Etuahof119a262016-08-19 15:54:22 +03001719 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301720 resultArray = new TConstantUnion[2];
1721 float f1, f2;
1722 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1723 resultArray[0].setFConst(f1);
1724 resultArray[1].setFConst(f2);
1725 break;
1726 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301727
Olli Etuahof119a262016-08-19 15:54:22 +03001728 case EOpPackUnorm2x16:
1729 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301730 ASSERT(getType().getNominalSize() == 2);
1731 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001732 resultArray->setUConst(
1733 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301734 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301735
Olli Etuahof119a262016-08-19 15:54:22 +03001736 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301737 {
Olli Etuahof119a262016-08-19 15:54:22 +03001738 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301739 resultArray = new TConstantUnion[2];
1740 float f1, f2;
1741 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1742 resultArray[0].setFConst(f1);
1743 resultArray[1].setFConst(f2);
1744 break;
1745 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301746
Olli Etuahof119a262016-08-19 15:54:22 +03001747 case EOpPackHalf2x16:
1748 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301749 ASSERT(getType().getNominalSize() == 2);
1750 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001751 resultArray->setUConst(
1752 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301753 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301754
Olli Etuahof119a262016-08-19 15:54:22 +03001755 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301756 {
Olli Etuahof119a262016-08-19 15:54:22 +03001757 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301758 resultArray = new TConstantUnion[2];
1759 float f1, f2;
1760 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1761 resultArray[0].setFConst(f1);
1762 resultArray[1].setFConst(f2);
1763 break;
1764 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301765
Olli Etuahof119a262016-08-19 15:54:22 +03001766 default:
1767 UNREACHABLE();
1768 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301769 }
1770
1771 return resultArray;
1772}
1773
Olli Etuahof119a262016-08-19 15:54:22 +03001774TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1775 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301776{
Olli Etuahof119a262016-08-19 15:54:22 +03001777 // Do unary operations where each component of the result is computed based on the corresponding
1778 // component of the operand. Also folds normalize, though the divisor in that case takes all
1779 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301780
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001781 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001782 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001783
1784 size_t objectSize = getType().getObjectSize();
1785
Arun Patoleab2b9a22015-07-06 18:27:56 +05301786 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1787 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301788 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001789 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301790 {
Olli Etuahof119a262016-08-19 15:54:22 +03001791 case EOpNegative:
1792 switch (getType().getBasicType())
1793 {
1794 case EbtFloat:
1795 resultArray[i].setFConst(-operandArray[i].getFConst());
1796 break;
1797 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001798 if (operandArray[i] == std::numeric_limits<int>::min())
1799 {
1800 // The minimum representable integer doesn't have a positive
1801 // counterpart, rather the negation overflows and in ESSL is supposed to
1802 // wrap back to the minimum representable integer. Make sure that we
1803 // don't actually let the negation overflow, which has undefined
1804 // behavior in C++.
1805 resultArray[i].setIConst(std::numeric_limits<int>::min());
1806 }
1807 else
1808 {
1809 resultArray[i].setIConst(-operandArray[i].getIConst());
1810 }
Olli Etuahof119a262016-08-19 15:54:22 +03001811 break;
1812 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001813 if (operandArray[i] == 0x80000000u)
1814 {
1815 resultArray[i].setUConst(0x80000000u);
1816 }
1817 else
1818 {
1819 resultArray[i].setUConst(static_cast<unsigned int>(
1820 -static_cast<int>(operandArray[i].getUConst())));
1821 }
Olli Etuahof119a262016-08-19 15:54:22 +03001822 break;
1823 default:
1824 UNREACHABLE();
1825 return nullptr;
1826 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301827 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301828
Olli Etuahof119a262016-08-19 15:54:22 +03001829 case EOpPositive:
1830 switch (getType().getBasicType())
1831 {
1832 case EbtFloat:
1833 resultArray[i].setFConst(operandArray[i].getFConst());
1834 break;
1835 case EbtInt:
1836 resultArray[i].setIConst(operandArray[i].getIConst());
1837 break;
1838 case EbtUInt:
1839 resultArray[i].setUConst(static_cast<unsigned int>(
1840 static_cast<int>(operandArray[i].getUConst())));
1841 break;
1842 default:
1843 UNREACHABLE();
1844 return nullptr;
1845 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301846 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301847
Olli Etuahof119a262016-08-19 15:54:22 +03001848 case EOpLogicalNot:
1849 switch (getType().getBasicType())
1850 {
1851 case EbtBool:
1852 resultArray[i].setBConst(!operandArray[i].getBConst());
1853 break;
1854 default:
1855 UNREACHABLE();
1856 return nullptr;
1857 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301858 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301859
Olli Etuahof119a262016-08-19 15:54:22 +03001860 case EOpBitwiseNot:
1861 switch (getType().getBasicType())
1862 {
1863 case EbtInt:
1864 resultArray[i].setIConst(~operandArray[i].getIConst());
1865 break;
1866 case EbtUInt:
1867 resultArray[i].setUConst(~operandArray[i].getUConst());
1868 break;
1869 default:
1870 UNREACHABLE();
1871 return nullptr;
1872 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301873 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301874
Olli Etuahof119a262016-08-19 15:54:22 +03001875 case EOpRadians:
1876 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301877 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1878 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301879
Olli Etuahof119a262016-08-19 15:54:22 +03001880 case EOpDegrees:
1881 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301882 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1883 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301884
Olli Etuahof119a262016-08-19 15:54:22 +03001885 case EOpSin:
1886 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301887 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301888
Olli Etuahof119a262016-08-19 15:54:22 +03001889 case EOpCos:
1890 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1891 break;
1892
1893 case EOpTan:
1894 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1895 break;
1896
1897 case EOpAsin:
1898 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1899 // 0.
1900 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1901 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1902 diagnostics, &resultArray[i]);
1903 else
1904 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1905 break;
1906
1907 case EOpAcos:
1908 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1909 // 0.
1910 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1911 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1912 diagnostics, &resultArray[i]);
1913 else
1914 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1915 break;
1916
1917 case EOpAtan:
1918 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1919 break;
1920
1921 case EOpSinh:
1922 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1923 break;
1924
1925 case EOpCosh:
1926 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1927 break;
1928
1929 case EOpTanh:
1930 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
1931 break;
1932
1933 case EOpAsinh:
1934 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
1935 break;
1936
1937 case EOpAcosh:
1938 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1939 if (operandArray[i].getFConst() < 1.0f)
1940 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1941 diagnostics, &resultArray[i]);
1942 else
1943 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
1944 break;
1945
1946 case EOpAtanh:
1947 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
1948 // 0.
1949 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
1950 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1951 diagnostics, &resultArray[i]);
1952 else
1953 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
1954 break;
1955
1956 case EOpAbs:
1957 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301958 {
Olli Etuahof119a262016-08-19 15:54:22 +03001959 case EbtFloat:
1960 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1961 break;
1962 case EbtInt:
1963 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1964 break;
1965 default:
1966 UNREACHABLE();
1967 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301968 }
1969 break;
Olli Etuahof119a262016-08-19 15:54:22 +03001970
1971 case EOpSign:
1972 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301973 {
Olli Etuahof119a262016-08-19 15:54:22 +03001974 case EbtFloat:
1975 {
1976 float fConst = operandArray[i].getFConst();
1977 float fResult = 0.0f;
1978 if (fConst > 0.0f)
1979 fResult = 1.0f;
1980 else if (fConst < 0.0f)
1981 fResult = -1.0f;
1982 resultArray[i].setFConst(fResult);
1983 break;
1984 }
1985 case EbtInt:
1986 {
1987 int iConst = operandArray[i].getIConst();
1988 int iResult = 0;
1989 if (iConst > 0)
1990 iResult = 1;
1991 else if (iConst < 0)
1992 iResult = -1;
1993 resultArray[i].setIConst(iResult);
1994 break;
1995 }
1996 default:
1997 UNREACHABLE();
1998 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301999 }
2000 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302001
Olli Etuahof119a262016-08-19 15:54:22 +03002002 case EOpFloor:
2003 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2004 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302005
Olli Etuahof119a262016-08-19 15:54:22 +03002006 case EOpTrunc:
2007 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2008 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302009
Olli Etuahof119a262016-08-19 15:54:22 +03002010 case EOpRound:
2011 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2012 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302013
Olli Etuahof119a262016-08-19 15:54:22 +03002014 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302015 {
Olli Etuahof119a262016-08-19 15:54:22 +03002016 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302017 float x = operandArray[i].getFConst();
2018 float result;
2019 float fractPart = modff(x, &result);
2020 if (fabsf(fractPart) == 0.5f)
2021 result = 2.0f * roundf(x / 2.0f);
2022 else
2023 result = roundf(x);
2024 resultArray[i].setFConst(result);
2025 break;
2026 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302027
Olli Etuahof119a262016-08-19 15:54:22 +03002028 case EOpCeil:
2029 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2030 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302031
Olli Etuahof119a262016-08-19 15:54:22 +03002032 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302033 {
Olli Etuahof119a262016-08-19 15:54:22 +03002034 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302035 float x = operandArray[i].getFConst();
2036 resultArray[i].setFConst(x - floorf(x));
2037 break;
2038 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302039
Olli Etuahof119a262016-08-19 15:54:22 +03002040 case EOpIsNan:
2041 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302042 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2043 break;
Arun Patole551279e2015-07-07 18:18:23 +05302044
Olli Etuahof119a262016-08-19 15:54:22 +03002045 case EOpIsInf:
2046 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302047 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2048 break;
Arun Patole551279e2015-07-07 18:18:23 +05302049
Olli Etuahof119a262016-08-19 15:54:22 +03002050 case EOpFloatBitsToInt:
2051 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302052 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2053 break;
Arun Patole551279e2015-07-07 18:18:23 +05302054
Olli Etuahof119a262016-08-19 15:54:22 +03002055 case EOpFloatBitsToUint:
2056 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302057 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2058 break;
Arun Patole551279e2015-07-07 18:18:23 +05302059
Olli Etuahof119a262016-08-19 15:54:22 +03002060 case EOpIntBitsToFloat:
2061 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302062 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2063 break;
Arun Patole551279e2015-07-07 18:18:23 +05302064
Olli Etuahof119a262016-08-19 15:54:22 +03002065 case EOpUintBitsToFloat:
2066 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302067 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2068 break;
Arun Patole551279e2015-07-07 18:18:23 +05302069
Olli Etuahof119a262016-08-19 15:54:22 +03002070 case EOpExp:
2071 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2072 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302073
Olli Etuahof119a262016-08-19 15:54:22 +03002074 case EOpLog:
2075 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2076 if (operandArray[i].getFConst() <= 0.0f)
2077 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2078 diagnostics, &resultArray[i]);
2079 else
2080 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2081 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302082
Olli Etuahof119a262016-08-19 15:54:22 +03002083 case EOpExp2:
2084 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2085 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302086
Olli Etuahof119a262016-08-19 15:54:22 +03002087 case EOpLog2:
2088 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2089 // And log2f is not available on some plarforms like old android, so just using
2090 // log(x)/log(2) here.
2091 if (operandArray[i].getFConst() <= 0.0f)
2092 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2093 diagnostics, &resultArray[i]);
2094 else
2095 {
2096 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2097 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2098 }
2099 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302100
Olli Etuahof119a262016-08-19 15:54:22 +03002101 case EOpSqrt:
2102 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2103 if (operandArray[i].getFConst() < 0.0f)
2104 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2105 diagnostics, &resultArray[i]);
2106 else
2107 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2108 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302109
Olli Etuahof119a262016-08-19 15:54:22 +03002110 case EOpInverseSqrt:
2111 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2112 // so getting the square root first using builtin function sqrt() and then taking
2113 // its inverse.
2114 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2115 // result to 0.
2116 if (operandArray[i].getFConst() <= 0.0f)
2117 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2118 diagnostics, &resultArray[i]);
2119 else
2120 {
2121 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2122 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2123 }
2124 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302125
Olli Etuahod68924e2017-01-02 17:34:40 +00002126 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002127 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302128 resultArray[i].setBConst(!operandArray[i].getBConst());
2129 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302130
Olli Etuahof119a262016-08-19 15:54:22 +03002131 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302132 {
Olli Etuahof119a262016-08-19 15:54:22 +03002133 ASSERT(getType().getBasicType() == EbtFloat);
2134 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302135 float length = VectorLength(operandArray, objectSize);
2136 if (length)
2137 resultArray[i].setFConst(x / length);
2138 else
Olli Etuahof119a262016-08-19 15:54:22 +03002139 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2140 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302141 break;
2142 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302143
Olli Etuahof119a262016-08-19 15:54:22 +03002144 case EOpDFdx:
2145 case EOpDFdy:
2146 case EOpFwidth:
2147 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302148 // Derivatives of constant arguments should be 0.
2149 resultArray[i].setFConst(0.0f);
2150 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302151
Olli Etuahof119a262016-08-19 15:54:22 +03002152 default:
2153 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302154 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302155 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002156
Arun Patoleab2b9a22015-07-06 18:27:56 +05302157 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002158}
2159
Olli Etuahof119a262016-08-19 15:54:22 +03002160void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2161 FloatTypeUnaryFunc builtinFunc,
2162 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302163{
2164 ASSERT(builtinFunc);
2165
Olli Etuahof119a262016-08-19 15:54:22 +03002166 ASSERT(getType().getBasicType() == EbtFloat);
2167 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302168}
2169
Jamie Madillb1a85f42014-08-19 15:23:24 -04002170// static
Olli Etuahof119a262016-08-19 15:54:22 +03002171TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002172{
2173 ASSERT(aggregate->getSequence()->size() > 0u);
2174 size_t resultSize = aggregate->getType().getObjectSize();
2175 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2176 TBasicType basicType = aggregate->getBasicType();
2177
2178 size_t resultIndex = 0u;
2179
2180 if (aggregate->getSequence()->size() == 1u)
2181 {
2182 TIntermNode *argument = aggregate->getSequence()->front();
2183 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2184 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2185 // Check the special case of constructing a matrix diagonal from a single scalar,
2186 // or a vector from a single scalar.
2187 if (argumentConstant->getType().getObjectSize() == 1u)
2188 {
2189 if (aggregate->isMatrix())
2190 {
2191 int resultCols = aggregate->getType().getCols();
2192 int resultRows = aggregate->getType().getRows();
2193 for (int col = 0; col < resultCols; ++col)
2194 {
2195 for (int row = 0; row < resultRows; ++row)
2196 {
2197 if (col == row)
2198 {
2199 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2200 }
2201 else
2202 {
2203 resultArray[resultIndex].setFConst(0.0f);
2204 }
2205 ++resultIndex;
2206 }
2207 }
2208 }
2209 else
2210 {
2211 while (resultIndex < resultSize)
2212 {
2213 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2214 ++resultIndex;
2215 }
2216 }
2217 ASSERT(resultIndex == resultSize);
2218 return resultArray;
2219 }
2220 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2221 {
2222 // The special case of constructing a matrix from a matrix.
2223 int argumentCols = argumentConstant->getType().getCols();
2224 int argumentRows = argumentConstant->getType().getRows();
2225 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002226 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002227 for (int col = 0; col < resultCols; ++col)
2228 {
2229 for (int row = 0; row < resultRows; ++row)
2230 {
2231 if (col < argumentCols && row < argumentRows)
2232 {
2233 resultArray[resultIndex].cast(basicType,
2234 argumentUnionArray[col * argumentRows + row]);
2235 }
2236 else if (col == row)
2237 {
2238 resultArray[resultIndex].setFConst(1.0f);
2239 }
2240 else
2241 {
2242 resultArray[resultIndex].setFConst(0.0f);
2243 }
2244 ++resultIndex;
2245 }
2246 }
2247 ASSERT(resultIndex == resultSize);
2248 return resultArray;
2249 }
2250 }
2251
2252 for (TIntermNode *&argument : *aggregate->getSequence())
2253 {
2254 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2255 size_t argumentSize = argumentConstant->getType().getObjectSize();
2256 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2257 for (size_t i = 0u; i < argumentSize; ++i)
2258 {
2259 if (resultIndex >= resultSize)
2260 break;
2261 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2262 ++resultIndex;
2263 }
2264 }
2265 ASSERT(resultIndex == resultSize);
2266 return resultArray;
2267}
2268
2269// static
Olli Etuahof119a262016-08-19 15:54:22 +03002270TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2271 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302272{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002273 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302274 TIntermSequence *sequence = aggregate->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002275 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002276 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302277 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002278 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302279 TBasicType basicType = EbtVoid;
2280 TSourceLoc loc;
2281 for (unsigned int i = 0; i < paramsCount; i++)
2282 {
2283 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002284 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302285
2286 if (i == 0)
2287 {
2288 basicType = paramConstant->getType().getBasicType();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002289 loc = paramConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302290 }
2291 unionArrays[i] = paramConstant->getUnionArrayPointer();
2292 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002293 if (objectSizes[i] > maxObjectSize)
2294 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302295 }
2296
Olli Etuahod5da5052016-08-29 13:16:55 +03002297 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302298 {
2299 for (unsigned int i = 0; i < paramsCount; i++)
2300 if (objectSizes[i] != maxObjectSize)
2301 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2302 }
Arun Patole274f0702015-05-05 13:33:30 +05302303
Olli Etuahob43846e2015-06-02 18:18:57 +03002304 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302305 if (paramsCount == 2)
2306 {
2307 //
2308 // Binary built-in
2309 //
2310 switch (op)
2311 {
Olli Etuahof119a262016-08-19 15:54:22 +03002312 case EOpAtan:
Arun Patolebf790422015-05-18 17:53:04 +05302313 {
Olli Etuahof119a262016-08-19 15:54:22 +03002314 ASSERT(basicType == EbtFloat);
2315 resultArray = new TConstantUnion[maxObjectSize];
2316 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302317 {
Olli Etuahof119a262016-08-19 15:54:22 +03002318 float y = unionArrays[0][i].getFConst();
2319 float x = unionArrays[1][i].getFConst();
2320 // Results are undefined if x and y are both 0.
2321 if (x == 0.0f && y == 0.0f)
2322 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2323 &resultArray[i]);
2324 else
2325 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302326 }
Olli Etuahof119a262016-08-19 15:54:22 +03002327 break;
Arun Patolebf790422015-05-18 17:53:04 +05302328 }
Arun Patolebf790422015-05-18 17:53:04 +05302329
Olli Etuahof119a262016-08-19 15:54:22 +03002330 case EOpPow:
Arun Patolebf790422015-05-18 17:53:04 +05302331 {
Olli Etuahof119a262016-08-19 15:54:22 +03002332 ASSERT(basicType == EbtFloat);
2333 resultArray = new TConstantUnion[maxObjectSize];
2334 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302335 {
Olli Etuahof119a262016-08-19 15:54:22 +03002336 float x = unionArrays[0][i].getFConst();
2337 float y = unionArrays[1][i].getFConst();
2338 // Results are undefined if x < 0.
2339 // Results are undefined if x = 0 and y <= 0.
2340 if (x < 0.0f)
2341 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2342 &resultArray[i]);
2343 else if (x == 0.0f && y <= 0.0f)
2344 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2345 &resultArray[i]);
2346 else
2347 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302348 }
Olli Etuahof119a262016-08-19 15:54:22 +03002349 break;
Arun Patolebf790422015-05-18 17:53:04 +05302350 }
Arun Patolebf790422015-05-18 17:53:04 +05302351
Olli Etuahof119a262016-08-19 15:54:22 +03002352 case EOpMod:
Arun Patolebf790422015-05-18 17:53:04 +05302353 {
Olli Etuahof119a262016-08-19 15:54:22 +03002354 ASSERT(basicType == EbtFloat);
2355 resultArray = new TConstantUnion[maxObjectSize];
2356 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302357 {
Olli Etuahof119a262016-08-19 15:54:22 +03002358 float x = unionArrays[0][i].getFConst();
2359 float y = unionArrays[1][i].getFConst();
2360 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302361 }
Olli Etuahof119a262016-08-19 15:54:22 +03002362 break;
Arun Patolebf790422015-05-18 17:53:04 +05302363 }
Arun Patolebf790422015-05-18 17:53:04 +05302364
Olli Etuahof119a262016-08-19 15:54:22 +03002365 case EOpMin:
Arun Patole274f0702015-05-05 13:33:30 +05302366 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002367 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302368 for (size_t i = 0; i < maxObjectSize; i++)
2369 {
2370 switch (basicType)
2371 {
Olli Etuahof119a262016-08-19 15:54:22 +03002372 case EbtFloat:
2373 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
2374 unionArrays[1][i].getFConst()));
2375 break;
2376 case EbtInt:
2377 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
2378 unionArrays[1][i].getIConst()));
2379 break;
2380 case EbtUInt:
2381 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
2382 unionArrays[1][i].getUConst()));
2383 break;
2384 default:
2385 UNREACHABLE();
2386 break;
Arun Patole274f0702015-05-05 13:33:30 +05302387 }
2388 }
Olli Etuahof119a262016-08-19 15:54:22 +03002389 break;
Arun Patole274f0702015-05-05 13:33:30 +05302390 }
Arun Patole274f0702015-05-05 13:33:30 +05302391
Olli Etuahof119a262016-08-19 15:54:22 +03002392 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302393 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002394 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302395 for (size_t i = 0; i < maxObjectSize; i++)
2396 {
2397 switch (basicType)
2398 {
Olli Etuahof119a262016-08-19 15:54:22 +03002399 case EbtFloat:
2400 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
2401 unionArrays[1][i].getFConst()));
2402 break;
2403 case EbtInt:
2404 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
2405 unionArrays[1][i].getIConst()));
2406 break;
2407 case EbtUInt:
2408 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
2409 unionArrays[1][i].getUConst()));
2410 break;
2411 default:
2412 UNREACHABLE();
2413 break;
Arun Patole274f0702015-05-05 13:33:30 +05302414 }
2415 }
Olli Etuahof119a262016-08-19 15:54:22 +03002416 break;
Arun Patole274f0702015-05-05 13:33:30 +05302417 }
Arun Patole274f0702015-05-05 13:33:30 +05302418
Olli Etuahof119a262016-08-19 15:54:22 +03002419 case EOpStep:
Arun Patolebf790422015-05-18 17:53:04 +05302420 {
Olli Etuahof119a262016-08-19 15:54:22 +03002421 ASSERT(basicType == EbtFloat);
2422 resultArray = new TConstantUnion[maxObjectSize];
2423 for (size_t i = 0; i < maxObjectSize; i++)
2424 resultArray[i].setFConst(
2425 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
2426 : 1.0f);
2427 break;
Arun Patolebf790422015-05-18 17:53:04 +05302428 }
Arun Patolebf790422015-05-18 17:53:04 +05302429
Olli Etuahoe1805592017-01-02 16:41:20 +00002430 case EOpLessThanComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302431 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002432 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302433 for (size_t i = 0; i < maxObjectSize; i++)
2434 {
2435 switch (basicType)
2436 {
Olli Etuahof119a262016-08-19 15:54:22 +03002437 case EbtFloat:
2438 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2439 unionArrays[1][i].getFConst());
2440 break;
2441 case EbtInt:
2442 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2443 unionArrays[1][i].getIConst());
2444 break;
2445 case EbtUInt:
2446 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2447 unionArrays[1][i].getUConst());
2448 break;
2449 default:
2450 UNREACHABLE();
2451 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302452 }
2453 }
Olli Etuahof119a262016-08-19 15:54:22 +03002454 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302455 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302456
Olli Etuahoe1805592017-01-02 16:41:20 +00002457 case EOpLessThanEqualComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302458 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002459 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302460 for (size_t i = 0; i < maxObjectSize; i++)
2461 {
2462 switch (basicType)
2463 {
Olli Etuahof119a262016-08-19 15:54:22 +03002464 case EbtFloat:
2465 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2466 unionArrays[1][i].getFConst());
2467 break;
2468 case EbtInt:
2469 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2470 unionArrays[1][i].getIConst());
2471 break;
2472 case EbtUInt:
2473 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2474 unionArrays[1][i].getUConst());
2475 break;
2476 default:
2477 UNREACHABLE();
2478 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302479 }
2480 }
Olli Etuahof119a262016-08-19 15:54:22 +03002481 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302482 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302483
Olli Etuahoe1805592017-01-02 16:41:20 +00002484 case EOpGreaterThanComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302485 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002486 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302487 for (size_t i = 0; i < maxObjectSize; i++)
2488 {
2489 switch (basicType)
2490 {
Olli Etuahof119a262016-08-19 15:54:22 +03002491 case EbtFloat:
2492 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2493 unionArrays[1][i].getFConst());
2494 break;
2495 case EbtInt:
2496 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2497 unionArrays[1][i].getIConst());
2498 break;
2499 case EbtUInt:
2500 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2501 unionArrays[1][i].getUConst());
2502 break;
2503 default:
2504 UNREACHABLE();
2505 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002506 }
2507 }
Olli Etuahof119a262016-08-19 15:54:22 +03002508 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302509 }
Olli Etuahoe1805592017-01-02 16:41:20 +00002510 case EOpGreaterThanEqualComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302511 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002512 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302513 for (size_t i = 0; i < maxObjectSize; i++)
2514 {
2515 switch (basicType)
2516 {
Olli Etuahof119a262016-08-19 15:54:22 +03002517 case EbtFloat:
2518 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2519 unionArrays[1][i].getFConst());
2520 break;
2521 case EbtInt:
2522 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2523 unionArrays[1][i].getIConst());
2524 break;
2525 case EbtUInt:
2526 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2527 unionArrays[1][i].getUConst());
2528 break;
2529 default:
2530 UNREACHABLE();
2531 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302532 }
2533 }
2534 }
2535 break;
2536
Olli Etuahoe1805592017-01-02 16:41:20 +00002537 case EOpEqualComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302538 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002539 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302540 for (size_t i = 0; i < maxObjectSize; i++)
2541 {
2542 switch (basicType)
2543 {
Olli Etuahof119a262016-08-19 15:54:22 +03002544 case EbtFloat:
2545 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2546 unionArrays[1][i].getFConst());
2547 break;
2548 case EbtInt:
2549 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2550 unionArrays[1][i].getIConst());
2551 break;
2552 case EbtUInt:
2553 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2554 unionArrays[1][i].getUConst());
2555 break;
2556 case EbtBool:
2557 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2558 unionArrays[1][i].getBConst());
2559 break;
2560 default:
2561 UNREACHABLE();
2562 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302563 }
2564 }
Olli Etuahof119a262016-08-19 15:54:22 +03002565 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302566 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302567
Olli Etuahoe1805592017-01-02 16:41:20 +00002568 case EOpNotEqualComponentWise:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302569 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002570 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302571 for (size_t i = 0; i < maxObjectSize; i++)
2572 {
2573 switch (basicType)
2574 {
Olli Etuahof119a262016-08-19 15:54:22 +03002575 case EbtFloat:
2576 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2577 unionArrays[1][i].getFConst());
2578 break;
2579 case EbtInt:
2580 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2581 unionArrays[1][i].getIConst());
2582 break;
2583 case EbtUInt:
2584 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2585 unionArrays[1][i].getUConst());
2586 break;
2587 case EbtBool:
2588 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2589 unionArrays[1][i].getBConst());
2590 break;
2591 default:
2592 UNREACHABLE();
2593 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302594 }
2595 }
Olli Etuahof119a262016-08-19 15:54:22 +03002596 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302597 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302598
Olli Etuahof119a262016-08-19 15:54:22 +03002599 case EOpDistance:
Arun Patole1155ddd2015-06-05 18:04:36 +05302600 {
Olli Etuahof119a262016-08-19 15:54:22 +03002601 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302602 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002603 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302604 for (size_t i = 0; i < maxObjectSize; i++)
2605 {
2606 float x = unionArrays[0][i].getFConst();
2607 float y = unionArrays[1][i].getFConst();
2608 distanceArray[i].setFConst(x - y);
2609 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002610 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Olli Etuahof119a262016-08-19 15:54:22 +03002611 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302612 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302613
Olli Etuahof119a262016-08-19 15:54:22 +03002614 case EOpDot:
2615 ASSERT(basicType == EbtFloat);
Olli Etuahob43846e2015-06-02 18:18:57 +03002616 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002617 resultArray->setFConst(
2618 VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2619 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302620
Olli Etuahof119a262016-08-19 15:54:22 +03002621 case EOpCross:
Arun Patole1155ddd2015-06-05 18:04:36 +05302622 {
Olli Etuahof119a262016-08-19 15:54:22 +03002623 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
Olli Etuahob43846e2015-06-02 18:18:57 +03002624 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002625 float x0 = unionArrays[0][0].getFConst();
2626 float x1 = unionArrays[0][1].getFConst();
2627 float x2 = unionArrays[0][2].getFConst();
2628 float y0 = unionArrays[1][0].getFConst();
2629 float y1 = unionArrays[1][1].getFConst();
2630 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002631 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2632 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2633 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Olli Etuahof119a262016-08-19 15:54:22 +03002634 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302635 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302636
Olli Etuahof119a262016-08-19 15:54:22 +03002637 case EOpReflect:
Arun Patole1155ddd2015-06-05 18:04:36 +05302638 {
Olli Etuahof119a262016-08-19 15:54:22 +03002639 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302640 // genType reflect (genType I, genType N) :
Olli Etuahof119a262016-08-19 15:54:22 +03002641 // For the incident vector I and surface orientation N, returns the reflection
2642 // direction:
Arun Patole1155ddd2015-06-05 18:04:36 +05302643 // I - 2 * dot(N, I) * N.
Olli Etuahof119a262016-08-19 15:54:22 +03002644 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302645 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2646 for (size_t i = 0; i < maxObjectSize; i++)
2647 {
2648 float result = unionArrays[0][i].getFConst() -
2649 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002650 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302651 }
Olli Etuahof119a262016-08-19 15:54:22 +03002652 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302653 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302654
Olli Etuahoe1805592017-01-02 16:41:20 +00002655 case EOpMulMatrixComponentWise:
Arun Patole7fa33552015-06-10 15:15:18 +05302656 {
Olli Etuahof119a262016-08-19 15:54:22 +03002657 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2658 (*sequence)[1]->getAsTyped()->isMatrix());
Arun Patole7fa33552015-06-10 15:15:18 +05302659 // Perform component-wise matrix multiplication.
2660 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002661 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302662 angle::Matrix<float> result =
2663 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2664 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002665 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302666 }
Arun Patole7fa33552015-06-10 15:15:18 +05302667
Olli Etuahof119a262016-08-19 15:54:22 +03002668 case EOpOuterProduct:
Arun Patole7fa33552015-06-10 15:15:18 +05302669 {
Olli Etuahof119a262016-08-19 15:54:22 +03002670 ASSERT(basicType == EbtFloat);
Arun Patole7fa33552015-06-10 15:15:18 +05302671 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2672 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuahof119a262016-08-19 15:54:22 +03002673 resultArray = new TConstantUnion[numRows * numCols];
Arun Patole7fa33552015-06-10 15:15:18 +05302674 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002675 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2676 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302677 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002678 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302679 }
Arun Patole7fa33552015-06-10 15:15:18 +05302680
Olli Etuahof119a262016-08-19 15:54:22 +03002681 default:
2682 UNREACHABLE();
2683 // TODO: Add constant folding support for other built-in operations that take 2
2684 // parameters and not handled above.
2685 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302686 }
2687 }
2688 else if (paramsCount == 3)
2689 {
2690 //
2691 // Ternary built-in
2692 //
2693 switch (op)
2694 {
Olli Etuahof119a262016-08-19 15:54:22 +03002695 case EOpClamp:
Arun Patole274f0702015-05-05 13:33:30 +05302696 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002697 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302698 for (size_t i = 0; i < maxObjectSize; i++)
2699 {
2700 switch (basicType)
2701 {
Olli Etuahof119a262016-08-19 15:54:22 +03002702 case EbtFloat:
Arun Patole274f0702015-05-05 13:33:30 +05302703 {
Olli Etuahof119a262016-08-19 15:54:22 +03002704 float x = unionArrays[0][i].getFConst();
Arun Patole274f0702015-05-05 13:33:30 +05302705 float min = unionArrays[1][i].getFConst();
2706 float max = unionArrays[2][i].getFConst();
2707 // Results are undefined if min > max.
2708 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002709 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2710 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302711 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002712 resultArray[i].setFConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002713 break;
Arun Patole274f0702015-05-05 13:33:30 +05302714 }
Olli Etuahof119a262016-08-19 15:54:22 +03002715
2716 case EbtInt:
Arun Patole274f0702015-05-05 13:33:30 +05302717 {
Olli Etuahof119a262016-08-19 15:54:22 +03002718 int x = unionArrays[0][i].getIConst();
Arun Patole274f0702015-05-05 13:33:30 +05302719 int min = unionArrays[1][i].getIConst();
2720 int max = unionArrays[2][i].getIConst();
2721 // Results are undefined if min > max.
2722 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002723 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2724 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302725 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002726 resultArray[i].setIConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002727 break;
Arun Patole274f0702015-05-05 13:33:30 +05302728 }
Olli Etuahof119a262016-08-19 15:54:22 +03002729 case EbtUInt:
Arun Patole274f0702015-05-05 13:33:30 +05302730 {
Olli Etuahof119a262016-08-19 15:54:22 +03002731 unsigned int x = unionArrays[0][i].getUConst();
Arun Patole274f0702015-05-05 13:33:30 +05302732 unsigned int min = unionArrays[1][i].getUConst();
2733 unsigned int max = unionArrays[2][i].getUConst();
2734 // Results are undefined if min > max.
2735 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002736 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2737 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302738 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002739 resultArray[i].setUConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002740 break;
Arun Patole274f0702015-05-05 13:33:30 +05302741 }
Olli Etuahof119a262016-08-19 15:54:22 +03002742 default:
2743 UNREACHABLE();
2744 break;
Arun Patole274f0702015-05-05 13:33:30 +05302745 }
2746 }
Olli Etuahof119a262016-08-19 15:54:22 +03002747 break;
Arun Patole274f0702015-05-05 13:33:30 +05302748 }
Arun Patole274f0702015-05-05 13:33:30 +05302749
Olli Etuahof119a262016-08-19 15:54:22 +03002750 case EOpMix:
Arun Patolebf790422015-05-18 17:53:04 +05302751 {
Olli Etuahof119a262016-08-19 15:54:22 +03002752 ASSERT(basicType == EbtFloat);
2753 resultArray = new TConstantUnion[maxObjectSize];
2754 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302755 {
Olli Etuahof119a262016-08-19 15:54:22 +03002756 float x = unionArrays[0][i].getFConst();
2757 float y = unionArrays[1][i].getFConst();
2758 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2759 if (type == EbtFloat)
Arun Patolebf790422015-05-18 17:53:04 +05302760 {
Olli Etuahof119a262016-08-19 15:54:22 +03002761 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2762 float a = unionArrays[2][i].getFConst();
2763 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2764 }
2765 else // 3rd parameter is EbtBool
2766 {
2767 ASSERT(type == EbtBool);
2768 // Selects which vector each returned component comes from.
2769 // For a component of a that is false, the corresponding component of x is
2770 // returned.
2771 // For a component of a that is true, the corresponding component of y is
2772 // returned.
2773 bool a = unionArrays[2][i].getBConst();
2774 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302775 }
2776 }
Olli Etuahof119a262016-08-19 15:54:22 +03002777 break;
Arun Patolebf790422015-05-18 17:53:04 +05302778 }
Arun Patolebf790422015-05-18 17:53:04 +05302779
Olli Etuahof119a262016-08-19 15:54:22 +03002780 case EOpSmoothStep:
Arun Patolebf790422015-05-18 17:53:04 +05302781 {
Olli Etuahof119a262016-08-19 15:54:22 +03002782 ASSERT(basicType == EbtFloat);
2783 resultArray = new TConstantUnion[maxObjectSize];
2784 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302785 {
Olli Etuahof119a262016-08-19 15:54:22 +03002786 float edge0 = unionArrays[0][i].getFConst();
2787 float edge1 = unionArrays[1][i].getFConst();
2788 float x = unionArrays[2][i].getFConst();
2789 // Results are undefined if edge0 >= edge1.
2790 if (edge0 >= edge1)
Arun Patolebf790422015-05-18 17:53:04 +05302791 {
Olli Etuahof119a262016-08-19 15:54:22 +03002792 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2793 &resultArray[i]);
2794 }
2795 else
2796 {
2797 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2798 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2799 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2800 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302801 }
2802 }
Olli Etuahof119a262016-08-19 15:54:22 +03002803 break;
Arun Patolebf790422015-05-18 17:53:04 +05302804 }
Arun Patolebf790422015-05-18 17:53:04 +05302805
Olli Etuahof119a262016-08-19 15:54:22 +03002806 case EOpFaceForward:
Arun Patole1155ddd2015-06-05 18:04:36 +05302807 {
Olli Etuahof119a262016-08-19 15:54:22 +03002808 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302809 // genType faceforward(genType N, genType I, genType Nref) :
2810 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahof119a262016-08-19 15:54:22 +03002811 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302812 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2813 for (size_t i = 0; i < maxObjectSize; i++)
2814 {
2815 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002816 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302817 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002818 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302819 }
Olli Etuahof119a262016-08-19 15:54:22 +03002820 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302821 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302822
Olli Etuahof119a262016-08-19 15:54:22 +03002823 case EOpRefract:
Arun Patole1155ddd2015-06-05 18:04:36 +05302824 {
Olli Etuahof119a262016-08-19 15:54:22 +03002825 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302826 // genType refract(genType I, genType N, float eta) :
Olli Etuahof119a262016-08-19 15:54:22 +03002827 // For the incident vector I and surface normal N, and the ratio of indices of
2828 // refraction eta,
Arun Patole1155ddd2015-06-05 18:04:36 +05302829 // return the refraction vector. The result is computed by
2830 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2831 // if (k < 0.0)
2832 // return genType(0.0)
2833 // else
2834 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahof119a262016-08-19 15:54:22 +03002835 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302836 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2837 for (size_t i = 0; i < maxObjectSize; i++)
2838 {
2839 float eta = unionArrays[2][i].getFConst();
Olli Etuahof119a262016-08-19 15:54:22 +03002840 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
Arun Patole1155ddd2015-06-05 18:04:36 +05302841 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002842 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302843 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002844 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Olli Etuahof119a262016-08-19 15:54:22 +03002845 (eta * dotProduct + sqrtf(k)) *
2846 unionArrays[1][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302847 }
Olli Etuahof119a262016-08-19 15:54:22 +03002848 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302849 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302850
Olli Etuahof119a262016-08-19 15:54:22 +03002851 default:
2852 UNREACHABLE();
2853 // TODO: Add constant folding support for other built-in operations that take 3
2854 // parameters and not handled above.
2855 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302856 }
2857 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002858 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302859}
2860
2861// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002862TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2863{
2864 if (hashFunction == NULL || name.empty())
2865 return name;
2866 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2867 TStringStream stream;
2868 stream << HASHED_NAME_PREFIX << std::hex << number;
2869 TString hashedName = stream.str();
2870 return hashedName;
2871}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002872
2873void TIntermTraverser::updateTree()
2874{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002875 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2876 {
2877 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2878 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002879 if (!insertion.insertionsAfter.empty())
2880 {
2881 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2882 insertion.insertionsAfter);
2883 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002884 }
2885 if (!insertion.insertionsBefore.empty())
2886 {
2887 bool inserted =
2888 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2889 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002890 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002891 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002892 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2893 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002894 const NodeUpdateEntry &replacement = mReplacements[ii];
2895 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002896 bool replaced =
2897 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002898 ASSERT(replaced);
2899
Olli Etuahocd94ef92015-04-16 19:18:10 +03002900 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002901 {
2902 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002903 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002904 // be replaced, we need to make sure we don't update the replaced
2905 // node; instead, we update the replacement node.
2906 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2907 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002908 NodeUpdateEntry &replacement2 = mReplacements[jj];
2909 if (replacement2.parent == replacement.original)
2910 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002911 }
2912 }
2913 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002914 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2915 {
2916 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2917 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002918 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
2919 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002920 ASSERT(replaced);
2921 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002922
Jamie Madill03d863c2016-07-27 18:15:53 -04002923 clearReplacementQueue();
2924}
2925
2926void TIntermTraverser::clearReplacementQueue()
2927{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002928 mReplacements.clear();
2929 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002930 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002931}
Jamie Madill1048e432016-07-23 18:51:28 -04002932
Jamie Madill03d863c2016-07-27 18:15:53 -04002933void TIntermTraverser::queueReplacement(TIntermNode *original,
2934 TIntermNode *replacement,
2935 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002936{
Jamie Madill03d863c2016-07-27 18:15:53 -04002937 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002938}
2939
Jamie Madill03d863c2016-07-27 18:15:53 -04002940void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2941 TIntermNode *original,
2942 TIntermNode *replacement,
2943 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002944{
Jamie Madill03d863c2016-07-27 18:15:53 -04002945 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2946 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002947}
Jamie Madill45bcc782016-11-07 13:58:48 -05002948
2949} // namespace sh