blob: 8a530b653ee8e8a8b1624925fd83397ed7004134 [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
841void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
842{
843 for (const int offset : mSwizzleOffsets)
844 {
845 switch (offset)
846 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500847 case 0:
848 *out << "x";
849 break;
850 case 1:
851 *out << "y";
852 break;
853 case 2:
854 *out << "z";
855 break;
856 case 3:
857 *out << "w";
858 break;
859 default:
860 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +0100861 }
862 }
863}
864
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100865TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
866 const TIntermTyped *left,
867 const TIntermTyped *right)
868{
869 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
870 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
871 right->getQualifier() != EvqConst)
872 {
873 return EvqTemporary;
874 }
875 return EvqConst;
876}
Olli Etuahob6fa0432016-09-28 16:28:05 +0100877
878// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300879void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400880{
Olli Etuaho1dded802016-08-18 18:13:13 +0300881 ASSERT(!isMultiplication() ||
882 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
883
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100884 // Comma is handled as a special case.
885 if (mOp == EOpComma)
886 {
887 setType(mRight->getType());
888 return;
889 }
890
Jamie Madillb1a85f42014-08-19 15:23:24 -0400891 // Base assumption: just make the type the same as the left
892 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400893 setType(mLeft->getType());
894
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200895 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400896 // Binary operations results in temporary variables unless both
897 // operands are const.
898 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
899 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200900 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400901 getTypePointer()->setQualifier(EvqTemporary);
902 }
903
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300904 // Handle indexing ops.
905 switch (mOp)
906 {
907 case EOpIndexDirect:
908 case EOpIndexIndirect:
909 if (mLeft->isArray())
910 {
911 mType.clearArrayness();
912 }
913 else if (mLeft->isMatrix())
914 {
915 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
916 static_cast<unsigned char>(mLeft->getRows())));
917 }
918 else if (mLeft->isVector())
919 {
920 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
921 }
922 else
923 {
924 UNREACHABLE();
925 }
926 return;
927 case EOpIndexDirectStruct:
928 {
929 const TFieldList &fields = mLeft->getType().getStruct()->fields();
930 const int i = mRight->getAsConstantUnion()->getIConst(0);
931 setType(*fields[i]->type());
932 getTypePointer()->setQualifier(resultQualifier);
933 return;
934 }
935 case EOpIndexDirectInterfaceBlock:
936 {
937 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
938 const int i = mRight->getAsConstantUnion()->getIConst(0);
939 setType(*fields[i]->type());
940 getTypePointer()->setQualifier(resultQualifier);
941 return;
942 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300943 default:
944 break;
945 }
946
947 ASSERT(mLeft->isArray() == mRight->isArray());
948
949 // The result gets promoted to the highest precision.
950 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
951 getTypePointer()->setPrecision(higherPrecision);
952
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500953 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400954
955 //
956 // All scalars or structs. Code after this test assumes this case is removed!
957 //
958 if (nominalSize == 1)
959 {
960 switch (mOp)
961 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500962 //
963 // Promote to conditional
964 //
965 case EOpEqual:
966 case EOpNotEqual:
967 case EOpLessThan:
968 case EOpGreaterThan:
969 case EOpLessThanEqual:
970 case EOpGreaterThanEqual:
971 setType(TType(EbtBool, EbpUndefined, resultQualifier));
972 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400973
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500974 //
975 // And and Or operate on conditionals
976 //
977 case EOpLogicalAnd:
978 case EOpLogicalXor:
979 case EOpLogicalOr:
980 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
981 setType(TType(EbtBool, EbpUndefined, resultQualifier));
982 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400983
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500984 default:
985 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400986 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300987 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400988 }
989
990 // If we reach here, at least one of the operands is vector or matrix.
991 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400992 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300993
Jamie Madillb1a85f42014-08-19 15:23:24 -0400994 switch (mOp)
995 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300996 case EOpMul:
997 break;
998 case EOpMatrixTimesScalar:
999 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001000 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001001 setType(TType(basicType, higherPrecision, resultQualifier,
1002 static_cast<unsigned char>(mRight->getCols()),
1003 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001004 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001005 break;
1006 case EOpMatrixTimesVector:
1007 setType(TType(basicType, higherPrecision, resultQualifier,
1008 static_cast<unsigned char>(mLeft->getRows()), 1));
1009 break;
1010 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001011 setType(TType(basicType, higherPrecision, resultQualifier,
1012 static_cast<unsigned char>(mRight->getCols()),
1013 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001014 break;
1015 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001016 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001017 static_cast<unsigned char>(nominalSize), 1));
1018 break;
1019 case EOpVectorTimesMatrix:
1020 setType(TType(basicType, higherPrecision, resultQualifier,
1021 static_cast<unsigned char>(mRight->getCols()), 1));
1022 break;
1023 case EOpMulAssign:
1024 case EOpVectorTimesScalarAssign:
1025 case EOpVectorTimesMatrixAssign:
1026 case EOpMatrixTimesScalarAssign:
1027 case EOpMatrixTimesMatrixAssign:
1028 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1029 break;
1030 case EOpAssign:
1031 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001032 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1033 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1034 break;
1035 case EOpAdd:
1036 case EOpSub:
1037 case EOpDiv:
1038 case EOpIMod:
1039 case EOpBitShiftLeft:
1040 case EOpBitShiftRight:
1041 case EOpBitwiseAnd:
1042 case EOpBitwiseXor:
1043 case EOpBitwiseOr:
1044 case EOpAddAssign:
1045 case EOpSubAssign:
1046 case EOpDivAssign:
1047 case EOpIModAssign:
1048 case EOpBitShiftLeftAssign:
1049 case EOpBitShiftRightAssign:
1050 case EOpBitwiseAndAssign:
1051 case EOpBitwiseXorAssign:
1052 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001053 {
1054 const int secondarySize =
1055 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1056 setType(TType(basicType, higherPrecision, resultQualifier,
1057 static_cast<unsigned char>(nominalSize),
1058 static_cast<unsigned char>(secondarySize)));
1059 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001060 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001061 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001062 case EOpEqual:
1063 case EOpNotEqual:
1064 case EOpLessThan:
1065 case EOpGreaterThan:
1066 case EOpLessThanEqual:
1067 case EOpGreaterThanEqual:
1068 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1069 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001070 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001071 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001072
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001073 case EOpIndexDirect:
1074 case EOpIndexIndirect:
1075 case EOpIndexDirectInterfaceBlock:
1076 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001077 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001078 UNREACHABLE();
1079 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001080 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001081 UNREACHABLE();
1082 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001083 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001084}
1085
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001086const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001087{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001088 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001089 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001090 ASSERT(index < static_cast<int>(getType().getArraySize()));
1091 TType arrayElementType = getType();
1092 arrayElementType.clearArrayness();
1093 size_t arrayElementSize = arrayElementType.getObjectSize();
1094 return &mUnionArrayPointer[arrayElementSize * index];
1095 }
1096 else if (isMatrix())
1097 {
1098 ASSERT(index < getType().getCols());
1099 int size = getType().getRows();
1100 return &mUnionArrayPointer[size * index];
1101 }
1102 else if (isVector())
1103 {
1104 ASSERT(index < getType().getNominalSize());
1105 return &mUnionArrayPointer[index];
1106 }
1107 else
1108 {
1109 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001110 return nullptr;
1111 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001112}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001113
Olli Etuahob6fa0432016-09-28 16:28:05 +01001114TIntermTyped *TIntermSwizzle::fold()
1115{
1116 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1117 if (operandConstant == nullptr)
1118 {
1119 return nullptr;
1120 }
1121
1122 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1123 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1124 {
1125 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1126 }
1127 return CreateFoldedNode(constArray, this, mType.getQualifier());
1128}
1129
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001130TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1131{
1132 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1133 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1134 switch (mOp)
1135 {
1136 case EOpIndexDirect:
1137 {
1138 if (leftConstant == nullptr || rightConstant == nullptr)
1139 {
1140 return nullptr;
1141 }
1142 int index = rightConstant->getIConst(0);
1143
1144 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1145 return CreateFoldedNode(constArray, this, mType.getQualifier());
1146 }
1147 case EOpIndexDirectStruct:
1148 {
1149 if (leftConstant == nullptr || rightConstant == nullptr)
1150 {
1151 return nullptr;
1152 }
1153 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1154 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1155
1156 size_t previousFieldsSize = 0;
1157 for (size_t i = 0; i < index; ++i)
1158 {
1159 previousFieldsSize += fields[i]->type()->getObjectSize();
1160 }
1161
1162 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1163 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1164 }
1165 case EOpIndexIndirect:
1166 case EOpIndexDirectInterfaceBlock:
1167 // Can never be constant folded.
1168 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001169 default:
1170 {
1171 if (leftConstant == nullptr || rightConstant == nullptr)
1172 {
1173 return nullptr;
1174 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001175 TConstantUnion *constArray =
1176 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001177
1178 // Nodes may be constant folded without being qualified as constant.
1179 return CreateFoldedNode(constArray, this, mType.getQualifier());
1180 }
1181 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001182}
1183
Olli Etuahof119a262016-08-19 15:54:22 +03001184TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001185{
1186 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1187 if (operandConstant == nullptr)
1188 {
1189 return nullptr;
1190 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301191
1192 TConstantUnion *constArray = nullptr;
1193 switch (mOp)
1194 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001195 case EOpAny:
1196 case EOpAll:
1197 case EOpLength:
1198 case EOpTranspose:
1199 case EOpDeterminant:
1200 case EOpInverse:
1201 case EOpPackSnorm2x16:
1202 case EOpUnpackSnorm2x16:
1203 case EOpPackUnorm2x16:
1204 case EOpUnpackUnorm2x16:
1205 case EOpPackHalf2x16:
1206 case EOpUnpackHalf2x16:
1207 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1208 break;
1209 default:
1210 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1211 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301212 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001213
1214 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001215 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001216}
1217
Olli Etuahof119a262016-08-19 15:54:22 +03001218TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001219{
1220 // Make sure that all params are constant before actual constant folding.
1221 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001222 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001223 if (param->getAsConstantUnion() == nullptr)
1224 {
1225 return nullptr;
1226 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001227 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001228 TConstantUnion *constArray = nullptr;
1229 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001230 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001231 else
Olli Etuahof119a262016-08-19 15:54:22 +03001232 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001233
1234 // Nodes may be constant folded without being qualified as constant.
1235 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
1236 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +03001237}
1238
Jamie Madillb1a85f42014-08-19 15:23:24 -04001239//
1240// The fold functions see if an operation on a constant can be done in place,
1241// without generating run-time code.
1242//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001243// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001244//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001245TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1246 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001247 TDiagnostics *diagnostics,
1248 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001249{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001250 const TConstantUnion *leftArray = getUnionArrayPointer();
1251 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001252
Olli Etuahof119a262016-08-19 15:54:22 +03001253 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001254
1255 size_t objectSize = getType().getObjectSize();
1256
1257 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1258 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1259 {
1260 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1261 }
1262 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1263 {
1264 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001265 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001266 objectSize = rightNode->getType().getObjectSize();
1267 }
1268
1269 TConstantUnion *resultArray = nullptr;
1270
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001271 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001272 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001273 case EOpAdd:
1274 resultArray = new TConstantUnion[objectSize];
1275 for (size_t i = 0; i < objectSize; i++)
1276 resultArray[i] =
1277 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1278 break;
1279 case EOpSub:
1280 resultArray = new TConstantUnion[objectSize];
1281 for (size_t i = 0; i < objectSize; i++)
1282 resultArray[i] =
1283 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1284 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001285
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001286 case EOpMul:
1287 case EOpVectorTimesScalar:
1288 case EOpMatrixTimesScalar:
1289 resultArray = new TConstantUnion[objectSize];
1290 for (size_t i = 0; i < objectSize; i++)
1291 resultArray[i] =
1292 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1293 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001294
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001295 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001296 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001297 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001298 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001299
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001300 const int leftCols = getCols();
1301 const int leftRows = getRows();
1302 const int rightCols = rightNode->getType().getCols();
1303 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001304 const int resultCols = rightCols;
1305 const int resultRows = leftRows;
1306
1307 resultArray = new TConstantUnion[resultCols * resultRows];
1308 for (int row = 0; row < resultRows; row++)
1309 {
1310 for (int column = 0; column < resultCols; column++)
1311 {
1312 resultArray[resultRows * column + row].setFConst(0.0f);
1313 for (int i = 0; i < leftCols; i++)
1314 {
1315 resultArray[resultRows * column + row].setFConst(
1316 resultArray[resultRows * column + row].getFConst() +
1317 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001318 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001319 }
1320 }
1321 }
1322 }
1323 break;
1324
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001325 case EOpDiv:
1326 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001327 {
1328 resultArray = new TConstantUnion[objectSize];
1329 for (size_t i = 0; i < objectSize; i++)
1330 {
1331 switch (getType().getBasicType())
1332 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001333 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001334 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001335 ASSERT(op == EOpDiv);
1336 float dividend = leftArray[i].getFConst();
1337 float divisor = rightArray[i].getFConst();
1338 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001339 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001340 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001341 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001342 diagnostics->warning(
1343 getLine(),
1344 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001345 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001346 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001347 }
1348 else
1349 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001350 diagnostics->warning(getLine(),
1351 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001352 bool negativeResult =
1353 std::signbit(dividend) != std::signbit(divisor);
1354 resultArray[i].setFConst(
1355 negativeResult ? -std::numeric_limits<float>::infinity()
1356 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001357 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001358 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001359 else if (gl::isInf(dividend) && gl::isInf(divisor))
1360 {
1361 diagnostics->warning(getLine(),
1362 "Infinity divided by infinity during constant "
1363 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001364 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001365 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1366 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001367 else
1368 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001369 float result = dividend / divisor;
1370 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001371 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001372 diagnostics->warning(
1373 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001374 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001375 }
1376 resultArray[i].setFConst(result);
1377 }
1378 break;
1379 }
1380 case EbtInt:
1381 if (rightArray[i] == 0)
1382 {
1383 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001384 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001385 resultArray[i].setIConst(INT_MAX);
1386 }
1387 else
1388 {
1389 int lhs = leftArray[i].getIConst();
1390 int divisor = rightArray[i].getIConst();
1391 if (op == EOpDiv)
1392 {
1393 // Check for the special case where the minimum representable number
1394 // is
1395 // divided by -1. If left alone this leads to integer overflow in
1396 // C++.
1397 // ESSL 3.00.6 section 4.1.3 Integers:
1398 // "However, for the case where the minimum representable value is
1399 // divided by -1, it is allowed to return either the minimum
1400 // representable value or the maximum representable value."
1401 if (lhs == -0x7fffffff - 1 && divisor == -1)
1402 {
1403 resultArray[i].setIConst(0x7fffffff);
1404 }
1405 else
1406 {
1407 resultArray[i].setIConst(lhs / divisor);
1408 }
Olli Etuahod4453572016-09-27 13:21:46 +01001409 }
1410 else
1411 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001412 ASSERT(op == EOpIMod);
1413 if (lhs < 0 || divisor < 0)
1414 {
1415 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1416 // when
1417 // either one of the operands is negative.
1418 diagnostics->warning(getLine(),
1419 "Negative modulus operator operand "
1420 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001421 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001422 resultArray[i].setIConst(0);
1423 }
1424 else
1425 {
1426 resultArray[i].setIConst(lhs % divisor);
1427 }
Olli Etuahod4453572016-09-27 13:21:46 +01001428 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001429 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001430 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001431
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001432 case EbtUInt:
1433 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001434 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001435 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001436 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001437 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001438 }
1439 else
1440 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001441 if (op == EOpDiv)
1442 {
1443 resultArray[i].setUConst(leftArray[i].getUConst() /
1444 rightArray[i].getUConst());
1445 }
1446 else
1447 {
1448 ASSERT(op == EOpIMod);
1449 resultArray[i].setUConst(leftArray[i].getUConst() %
1450 rightArray[i].getUConst());
1451 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001452 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001453 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001454
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001455 default:
1456 UNREACHABLE();
1457 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001458 }
1459 }
1460 }
1461 break;
1462
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001463 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001464 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001465 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001466 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001467
1468 const int matrixCols = getCols();
1469 const int matrixRows = getRows();
1470
1471 resultArray = new TConstantUnion[matrixRows];
1472
1473 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1474 {
1475 resultArray[matrixRow].setFConst(0.0f);
1476 for (int col = 0; col < matrixCols; col++)
1477 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001478 resultArray[matrixRow].setFConst(
1479 resultArray[matrixRow].getFConst() +
1480 leftArray[col * matrixRows + matrixRow].getFConst() *
1481 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001482 }
1483 }
1484 }
1485 break;
1486
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001487 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001488 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001489 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001490 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001491
1492 const int matrixCols = rightNode->getType().getCols();
1493 const int matrixRows = rightNode->getType().getRows();
1494
1495 resultArray = new TConstantUnion[matrixCols];
1496
1497 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1498 {
1499 resultArray[matrixCol].setFConst(0.0f);
1500 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1501 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001502 resultArray[matrixCol].setFConst(
1503 resultArray[matrixCol].getFConst() +
1504 leftArray[matrixRow].getFConst() *
1505 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001506 }
1507 }
1508 }
1509 break;
1510
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001511 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001512 {
1513 resultArray = new TConstantUnion[objectSize];
1514 for (size_t i = 0; i < objectSize; i++)
1515 {
1516 resultArray[i] = leftArray[i] && rightArray[i];
1517 }
1518 }
1519 break;
1520
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001521 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001522 {
1523 resultArray = new TConstantUnion[objectSize];
1524 for (size_t i = 0; i < objectSize; i++)
1525 {
1526 resultArray[i] = leftArray[i] || rightArray[i];
1527 }
1528 }
1529 break;
1530
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001531 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001532 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001533 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001534 resultArray = new TConstantUnion[objectSize];
1535 for (size_t i = 0; i < objectSize; i++)
1536 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001537 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001538 }
1539 }
1540 break;
1541
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001542 case EOpBitwiseAnd:
1543 resultArray = new TConstantUnion[objectSize];
1544 for (size_t i = 0; i < objectSize; i++)
1545 resultArray[i] = leftArray[i] & rightArray[i];
1546 break;
1547 case EOpBitwiseXor:
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 EOpBitwiseOr:
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 EOpBitShiftLeft:
1558 resultArray = new TConstantUnion[objectSize];
1559 for (size_t i = 0; i < objectSize; i++)
1560 resultArray[i] =
1561 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1562 break;
1563 case EOpBitShiftRight:
1564 resultArray = new TConstantUnion[objectSize];
1565 for (size_t i = 0; i < objectSize; i++)
1566 resultArray[i] =
1567 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1568 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001569
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001570 case EOpLessThan:
1571 ASSERT(objectSize == 1);
1572 resultArray = new TConstantUnion[1];
1573 resultArray->setBConst(*leftArray < *rightArray);
1574 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001575
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001576 case EOpGreaterThan:
1577 ASSERT(objectSize == 1);
1578 resultArray = new TConstantUnion[1];
1579 resultArray->setBConst(*leftArray > *rightArray);
1580 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001581
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001582 case EOpLessThanEqual:
1583 ASSERT(objectSize == 1);
1584 resultArray = new TConstantUnion[1];
1585 resultArray->setBConst(!(*leftArray > *rightArray));
1586 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001587
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001588 case EOpGreaterThanEqual:
1589 ASSERT(objectSize == 1);
1590 resultArray = new TConstantUnion[1];
1591 resultArray->setBConst(!(*leftArray < *rightArray));
1592 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001593
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001594 case EOpEqual:
1595 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001596 {
1597 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001598 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001599 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001600 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001601 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001602 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001603 equal = false;
1604 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001605 }
1606 }
1607 if (op == EOpEqual)
1608 {
1609 resultArray->setBConst(equal);
1610 }
1611 else
1612 {
1613 resultArray->setBConst(!equal);
1614 }
1615 }
1616 break;
1617
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 default:
1619 UNREACHABLE();
1620 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001621 }
1622 return resultArray;
1623}
1624
Olli Etuahof119a262016-08-19 15:54:22 +03001625// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1626// code. Returns the constant value to keep using. Nullptr should not be returned.
1627TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001628{
Olli Etuahof119a262016-08-19 15:54:22 +03001629 // Do operations where the return type may have a different number of components compared to the
1630 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001631
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001632 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001633 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301634
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001635 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301636 TConstantUnion *resultArray = nullptr;
1637 switch (op)
1638 {
Olli Etuahof119a262016-08-19 15:54:22 +03001639 case EOpAny:
1640 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301641 resultArray = new TConstantUnion();
1642 resultArray->setBConst(false);
1643 for (size_t i = 0; i < objectSize; i++)
1644 {
1645 if (operandArray[i].getBConst())
1646 {
1647 resultArray->setBConst(true);
1648 break;
1649 }
1650 }
1651 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301652
Olli Etuahof119a262016-08-19 15:54:22 +03001653 case EOpAll:
1654 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301655 resultArray = new TConstantUnion();
1656 resultArray->setBConst(true);
1657 for (size_t i = 0; i < objectSize; i++)
1658 {
1659 if (!operandArray[i].getBConst())
1660 {
1661 resultArray->setBConst(false);
1662 break;
1663 }
1664 }
1665 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301666
Olli Etuahof119a262016-08-19 15:54:22 +03001667 case EOpLength:
1668 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301669 resultArray = new TConstantUnion();
1670 resultArray->setFConst(VectorLength(operandArray, objectSize));
1671 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301672
Olli Etuahof119a262016-08-19 15:54:22 +03001673 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301674 {
Olli Etuahof119a262016-08-19 15:54:22 +03001675 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301676 resultArray = new TConstantUnion[objectSize];
1677 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001678 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301679 SetUnionArrayFromMatrix(result, resultArray);
1680 break;
1681 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301682
Olli Etuahof119a262016-08-19 15:54:22 +03001683 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301684 {
Olli Etuahof119a262016-08-19 15:54:22 +03001685 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301686 unsigned int size = getType().getNominalSize();
1687 ASSERT(size >= 2 && size <= 4);
1688 resultArray = new TConstantUnion();
1689 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1690 break;
1691 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301692
Olli Etuahof119a262016-08-19 15:54:22 +03001693 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301694 {
Olli Etuahof119a262016-08-19 15:54:22 +03001695 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301696 unsigned int size = getType().getNominalSize();
1697 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001698 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301699 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1700 SetUnionArrayFromMatrix(result, resultArray);
1701 break;
1702 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301703
Olli Etuahof119a262016-08-19 15:54:22 +03001704 case EOpPackSnorm2x16:
1705 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301706 ASSERT(getType().getNominalSize() == 2);
1707 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001708 resultArray->setUConst(
1709 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301710 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301711
Olli Etuahof119a262016-08-19 15:54:22 +03001712 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301713 {
Olli Etuahof119a262016-08-19 15:54:22 +03001714 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301715 resultArray = new TConstantUnion[2];
1716 float f1, f2;
1717 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1718 resultArray[0].setFConst(f1);
1719 resultArray[1].setFConst(f2);
1720 break;
1721 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301722
Olli Etuahof119a262016-08-19 15:54:22 +03001723 case EOpPackUnorm2x16:
1724 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301725 ASSERT(getType().getNominalSize() == 2);
1726 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001727 resultArray->setUConst(
1728 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301729 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301730
Olli Etuahof119a262016-08-19 15:54:22 +03001731 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301732 {
Olli Etuahof119a262016-08-19 15:54:22 +03001733 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301734 resultArray = new TConstantUnion[2];
1735 float f1, f2;
1736 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1737 resultArray[0].setFConst(f1);
1738 resultArray[1].setFConst(f2);
1739 break;
1740 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301741
Olli Etuahof119a262016-08-19 15:54:22 +03001742 case EOpPackHalf2x16:
1743 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301744 ASSERT(getType().getNominalSize() == 2);
1745 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001746 resultArray->setUConst(
1747 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301748 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301749
Olli Etuahof119a262016-08-19 15:54:22 +03001750 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301751 {
Olli Etuahof119a262016-08-19 15:54:22 +03001752 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301753 resultArray = new TConstantUnion[2];
1754 float f1, f2;
1755 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1756 resultArray[0].setFConst(f1);
1757 resultArray[1].setFConst(f2);
1758 break;
1759 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301760
Olli Etuahof119a262016-08-19 15:54:22 +03001761 default:
1762 UNREACHABLE();
1763 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301764 }
1765
1766 return resultArray;
1767}
1768
Olli Etuahof119a262016-08-19 15:54:22 +03001769TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1770 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301771{
Olli Etuahof119a262016-08-19 15:54:22 +03001772 // Do unary operations where each component of the result is computed based on the corresponding
1773 // component of the operand. Also folds normalize, though the divisor in that case takes all
1774 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301775
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001776 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001777 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001778
1779 size_t objectSize = getType().getObjectSize();
1780
Arun Patoleab2b9a22015-07-06 18:27:56 +05301781 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1782 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301783 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001784 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301785 {
Olli Etuahof119a262016-08-19 15:54:22 +03001786 case EOpNegative:
1787 switch (getType().getBasicType())
1788 {
1789 case EbtFloat:
1790 resultArray[i].setFConst(-operandArray[i].getFConst());
1791 break;
1792 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001793 if (operandArray[i] == std::numeric_limits<int>::min())
1794 {
1795 // The minimum representable integer doesn't have a positive
1796 // counterpart, rather the negation overflows and in ESSL is supposed to
1797 // wrap back to the minimum representable integer. Make sure that we
1798 // don't actually let the negation overflow, which has undefined
1799 // behavior in C++.
1800 resultArray[i].setIConst(std::numeric_limits<int>::min());
1801 }
1802 else
1803 {
1804 resultArray[i].setIConst(-operandArray[i].getIConst());
1805 }
Olli Etuahof119a262016-08-19 15:54:22 +03001806 break;
1807 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001808 if (operandArray[i] == 0x80000000u)
1809 {
1810 resultArray[i].setUConst(0x80000000u);
1811 }
1812 else
1813 {
1814 resultArray[i].setUConst(static_cast<unsigned int>(
1815 -static_cast<int>(operandArray[i].getUConst())));
1816 }
Olli Etuahof119a262016-08-19 15:54:22 +03001817 break;
1818 default:
1819 UNREACHABLE();
1820 return nullptr;
1821 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301822 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301823
Olli Etuahof119a262016-08-19 15:54:22 +03001824 case EOpPositive:
1825 switch (getType().getBasicType())
1826 {
1827 case EbtFloat:
1828 resultArray[i].setFConst(operandArray[i].getFConst());
1829 break;
1830 case EbtInt:
1831 resultArray[i].setIConst(operandArray[i].getIConst());
1832 break;
1833 case EbtUInt:
1834 resultArray[i].setUConst(static_cast<unsigned int>(
1835 static_cast<int>(operandArray[i].getUConst())));
1836 break;
1837 default:
1838 UNREACHABLE();
1839 return nullptr;
1840 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301841 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301842
Olli Etuahof119a262016-08-19 15:54:22 +03001843 case EOpLogicalNot:
1844 switch (getType().getBasicType())
1845 {
1846 case EbtBool:
1847 resultArray[i].setBConst(!operandArray[i].getBConst());
1848 break;
1849 default:
1850 UNREACHABLE();
1851 return nullptr;
1852 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301853 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301854
Olli Etuahof119a262016-08-19 15:54:22 +03001855 case EOpBitwiseNot:
1856 switch (getType().getBasicType())
1857 {
1858 case EbtInt:
1859 resultArray[i].setIConst(~operandArray[i].getIConst());
1860 break;
1861 case EbtUInt:
1862 resultArray[i].setUConst(~operandArray[i].getUConst());
1863 break;
1864 default:
1865 UNREACHABLE();
1866 return nullptr;
1867 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301868 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301869
Olli Etuahof119a262016-08-19 15:54:22 +03001870 case EOpRadians:
1871 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301872 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1873 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301874
Olli Etuahof119a262016-08-19 15:54:22 +03001875 case EOpDegrees:
1876 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301877 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1878 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301879
Olli Etuahof119a262016-08-19 15:54:22 +03001880 case EOpSin:
1881 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301882 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301883
Olli Etuahof119a262016-08-19 15:54:22 +03001884 case EOpCos:
1885 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1886 break;
1887
1888 case EOpTan:
1889 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1890 break;
1891
1892 case EOpAsin:
1893 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1894 // 0.
1895 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1896 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1897 diagnostics, &resultArray[i]);
1898 else
1899 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1900 break;
1901
1902 case EOpAcos:
1903 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1904 // 0.
1905 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1906 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1907 diagnostics, &resultArray[i]);
1908 else
1909 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1910 break;
1911
1912 case EOpAtan:
1913 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1914 break;
1915
1916 case EOpSinh:
1917 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1918 break;
1919
1920 case EOpCosh:
1921 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1922 break;
1923
1924 case EOpTanh:
1925 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
1926 break;
1927
1928 case EOpAsinh:
1929 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
1930 break;
1931
1932 case EOpAcosh:
1933 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1934 if (operandArray[i].getFConst() < 1.0f)
1935 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1936 diagnostics, &resultArray[i]);
1937 else
1938 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
1939 break;
1940
1941 case EOpAtanh:
1942 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
1943 // 0.
1944 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
1945 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1946 diagnostics, &resultArray[i]);
1947 else
1948 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
1949 break;
1950
1951 case EOpAbs:
1952 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301953 {
Olli Etuahof119a262016-08-19 15:54:22 +03001954 case EbtFloat:
1955 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1956 break;
1957 case EbtInt:
1958 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1959 break;
1960 default:
1961 UNREACHABLE();
1962 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301963 }
1964 break;
Olli Etuahof119a262016-08-19 15:54:22 +03001965
1966 case EOpSign:
1967 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301968 {
Olli Etuahof119a262016-08-19 15:54:22 +03001969 case EbtFloat:
1970 {
1971 float fConst = operandArray[i].getFConst();
1972 float fResult = 0.0f;
1973 if (fConst > 0.0f)
1974 fResult = 1.0f;
1975 else if (fConst < 0.0f)
1976 fResult = -1.0f;
1977 resultArray[i].setFConst(fResult);
1978 break;
1979 }
1980 case EbtInt:
1981 {
1982 int iConst = operandArray[i].getIConst();
1983 int iResult = 0;
1984 if (iConst > 0)
1985 iResult = 1;
1986 else if (iConst < 0)
1987 iResult = -1;
1988 resultArray[i].setIConst(iResult);
1989 break;
1990 }
1991 default:
1992 UNREACHABLE();
1993 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301994 }
1995 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301996
Olli Etuahof119a262016-08-19 15:54:22 +03001997 case EOpFloor:
1998 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
1999 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302000
Olli Etuahof119a262016-08-19 15:54:22 +03002001 case EOpTrunc:
2002 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2003 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302004
Olli Etuahof119a262016-08-19 15:54:22 +03002005 case EOpRound:
2006 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2007 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302008
Olli Etuahof119a262016-08-19 15:54:22 +03002009 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302010 {
Olli Etuahof119a262016-08-19 15:54:22 +03002011 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302012 float x = operandArray[i].getFConst();
2013 float result;
2014 float fractPart = modff(x, &result);
2015 if (fabsf(fractPart) == 0.5f)
2016 result = 2.0f * roundf(x / 2.0f);
2017 else
2018 result = roundf(x);
2019 resultArray[i].setFConst(result);
2020 break;
2021 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302022
Olli Etuahof119a262016-08-19 15:54:22 +03002023 case EOpCeil:
2024 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2025 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302026
Olli Etuahof119a262016-08-19 15:54:22 +03002027 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302028 {
Olli Etuahof119a262016-08-19 15:54:22 +03002029 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302030 float x = operandArray[i].getFConst();
2031 resultArray[i].setFConst(x - floorf(x));
2032 break;
2033 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302034
Olli Etuahof119a262016-08-19 15:54:22 +03002035 case EOpIsNan:
2036 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302037 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2038 break;
Arun Patole551279e2015-07-07 18:18:23 +05302039
Olli Etuahof119a262016-08-19 15:54:22 +03002040 case EOpIsInf:
2041 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302042 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2043 break;
Arun Patole551279e2015-07-07 18:18:23 +05302044
Olli Etuahof119a262016-08-19 15:54:22 +03002045 case EOpFloatBitsToInt:
2046 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302047 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2048 break;
Arun Patole551279e2015-07-07 18:18:23 +05302049
Olli Etuahof119a262016-08-19 15:54:22 +03002050 case EOpFloatBitsToUint:
2051 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302052 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2053 break;
Arun Patole551279e2015-07-07 18:18:23 +05302054
Olli Etuahof119a262016-08-19 15:54:22 +03002055 case EOpIntBitsToFloat:
2056 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302057 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2058 break;
Arun Patole551279e2015-07-07 18:18:23 +05302059
Olli Etuahof119a262016-08-19 15:54:22 +03002060 case EOpUintBitsToFloat:
2061 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302062 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2063 break;
Arun Patole551279e2015-07-07 18:18:23 +05302064
Olli Etuahof119a262016-08-19 15:54:22 +03002065 case EOpExp:
2066 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2067 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302068
Olli Etuahof119a262016-08-19 15:54:22 +03002069 case EOpLog:
2070 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2071 if (operandArray[i].getFConst() <= 0.0f)
2072 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2073 diagnostics, &resultArray[i]);
2074 else
2075 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2076 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302077
Olli Etuahof119a262016-08-19 15:54:22 +03002078 case EOpExp2:
2079 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2080 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302081
Olli Etuahof119a262016-08-19 15:54:22 +03002082 case EOpLog2:
2083 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2084 // And log2f is not available on some plarforms like old android, so just using
2085 // log(x)/log(2) here.
2086 if (operandArray[i].getFConst() <= 0.0f)
2087 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2088 diagnostics, &resultArray[i]);
2089 else
2090 {
2091 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2092 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2093 }
2094 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302095
Olli Etuahof119a262016-08-19 15:54:22 +03002096 case EOpSqrt:
2097 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2098 if (operandArray[i].getFConst() < 0.0f)
2099 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2100 diagnostics, &resultArray[i]);
2101 else
2102 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2103 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302104
Olli Etuahof119a262016-08-19 15:54:22 +03002105 case EOpInverseSqrt:
2106 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2107 // so getting the square root first using builtin function sqrt() and then taking
2108 // its inverse.
2109 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2110 // result to 0.
2111 if (operandArray[i].getFConst() <= 0.0f)
2112 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2113 diagnostics, &resultArray[i]);
2114 else
2115 {
2116 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2117 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2118 }
2119 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302120
Olli Etuahof119a262016-08-19 15:54:22 +03002121 case EOpVectorLogicalNot:
2122 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302123 resultArray[i].setBConst(!operandArray[i].getBConst());
2124 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302125
Olli Etuahof119a262016-08-19 15:54:22 +03002126 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302127 {
Olli Etuahof119a262016-08-19 15:54:22 +03002128 ASSERT(getType().getBasicType() == EbtFloat);
2129 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302130 float length = VectorLength(operandArray, objectSize);
2131 if (length)
2132 resultArray[i].setFConst(x / length);
2133 else
Olli Etuahof119a262016-08-19 15:54:22 +03002134 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2135 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136 break;
2137 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302138
Olli Etuahof119a262016-08-19 15:54:22 +03002139 case EOpDFdx:
2140 case EOpDFdy:
2141 case EOpFwidth:
2142 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302143 // Derivatives of constant arguments should be 0.
2144 resultArray[i].setFConst(0.0f);
2145 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302146
Olli Etuahof119a262016-08-19 15:54:22 +03002147 default:
2148 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302149 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302150 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002151
Arun Patoleab2b9a22015-07-06 18:27:56 +05302152 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002153}
2154
Olli Etuahof119a262016-08-19 15:54:22 +03002155void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2156 FloatTypeUnaryFunc builtinFunc,
2157 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302158{
2159 ASSERT(builtinFunc);
2160
Olli Etuahof119a262016-08-19 15:54:22 +03002161 ASSERT(getType().getBasicType() == EbtFloat);
2162 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302163}
2164
Jamie Madillb1a85f42014-08-19 15:23:24 -04002165// static
Olli Etuahof119a262016-08-19 15:54:22 +03002166TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002167{
2168 ASSERT(aggregate->getSequence()->size() > 0u);
2169 size_t resultSize = aggregate->getType().getObjectSize();
2170 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2171 TBasicType basicType = aggregate->getBasicType();
2172
2173 size_t resultIndex = 0u;
2174
2175 if (aggregate->getSequence()->size() == 1u)
2176 {
2177 TIntermNode *argument = aggregate->getSequence()->front();
2178 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2179 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2180 // Check the special case of constructing a matrix diagonal from a single scalar,
2181 // or a vector from a single scalar.
2182 if (argumentConstant->getType().getObjectSize() == 1u)
2183 {
2184 if (aggregate->isMatrix())
2185 {
2186 int resultCols = aggregate->getType().getCols();
2187 int resultRows = aggregate->getType().getRows();
2188 for (int col = 0; col < resultCols; ++col)
2189 {
2190 for (int row = 0; row < resultRows; ++row)
2191 {
2192 if (col == row)
2193 {
2194 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2195 }
2196 else
2197 {
2198 resultArray[resultIndex].setFConst(0.0f);
2199 }
2200 ++resultIndex;
2201 }
2202 }
2203 }
2204 else
2205 {
2206 while (resultIndex < resultSize)
2207 {
2208 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2209 ++resultIndex;
2210 }
2211 }
2212 ASSERT(resultIndex == resultSize);
2213 return resultArray;
2214 }
2215 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2216 {
2217 // The special case of constructing a matrix from a matrix.
2218 int argumentCols = argumentConstant->getType().getCols();
2219 int argumentRows = argumentConstant->getType().getRows();
2220 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002221 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002222 for (int col = 0; col < resultCols; ++col)
2223 {
2224 for (int row = 0; row < resultRows; ++row)
2225 {
2226 if (col < argumentCols && row < argumentRows)
2227 {
2228 resultArray[resultIndex].cast(basicType,
2229 argumentUnionArray[col * argumentRows + row]);
2230 }
2231 else if (col == row)
2232 {
2233 resultArray[resultIndex].setFConst(1.0f);
2234 }
2235 else
2236 {
2237 resultArray[resultIndex].setFConst(0.0f);
2238 }
2239 ++resultIndex;
2240 }
2241 }
2242 ASSERT(resultIndex == resultSize);
2243 return resultArray;
2244 }
2245 }
2246
2247 for (TIntermNode *&argument : *aggregate->getSequence())
2248 {
2249 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2250 size_t argumentSize = argumentConstant->getType().getObjectSize();
2251 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2252 for (size_t i = 0u; i < argumentSize; ++i)
2253 {
2254 if (resultIndex >= resultSize)
2255 break;
2256 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2257 ++resultIndex;
2258 }
2259 }
2260 ASSERT(resultIndex == resultSize);
2261 return resultArray;
2262}
2263
2264// static
Olli Etuahof119a262016-08-19 15:54:22 +03002265TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2266 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302267{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002268 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302269 TIntermSequence *sequence = aggregate->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002270 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002271 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302272 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002273 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302274 TBasicType basicType = EbtVoid;
2275 TSourceLoc loc;
2276 for (unsigned int i = 0; i < paramsCount; i++)
2277 {
2278 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002279 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302280
2281 if (i == 0)
2282 {
2283 basicType = paramConstant->getType().getBasicType();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002284 loc = paramConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302285 }
2286 unionArrays[i] = paramConstant->getUnionArrayPointer();
2287 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002288 if (objectSizes[i] > maxObjectSize)
2289 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302290 }
2291
Olli Etuahod5da5052016-08-29 13:16:55 +03002292 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302293 {
2294 for (unsigned int i = 0; i < paramsCount; i++)
2295 if (objectSizes[i] != maxObjectSize)
2296 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2297 }
Arun Patole274f0702015-05-05 13:33:30 +05302298
Olli Etuahob43846e2015-06-02 18:18:57 +03002299 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302300 if (paramsCount == 2)
2301 {
2302 //
2303 // Binary built-in
2304 //
2305 switch (op)
2306 {
Olli Etuahof119a262016-08-19 15:54:22 +03002307 case EOpAtan:
Arun Patolebf790422015-05-18 17:53:04 +05302308 {
Olli Etuahof119a262016-08-19 15:54:22 +03002309 ASSERT(basicType == EbtFloat);
2310 resultArray = new TConstantUnion[maxObjectSize];
2311 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302312 {
Olli Etuahof119a262016-08-19 15:54:22 +03002313 float y = unionArrays[0][i].getFConst();
2314 float x = unionArrays[1][i].getFConst();
2315 // Results are undefined if x and y are both 0.
2316 if (x == 0.0f && y == 0.0f)
2317 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2318 &resultArray[i]);
2319 else
2320 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302321 }
Olli Etuahof119a262016-08-19 15:54:22 +03002322 break;
Arun Patolebf790422015-05-18 17:53:04 +05302323 }
Arun Patolebf790422015-05-18 17:53:04 +05302324
Olli Etuahof119a262016-08-19 15:54:22 +03002325 case EOpPow:
Arun Patolebf790422015-05-18 17:53:04 +05302326 {
Olli Etuahof119a262016-08-19 15:54:22 +03002327 ASSERT(basicType == EbtFloat);
2328 resultArray = new TConstantUnion[maxObjectSize];
2329 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302330 {
Olli Etuahof119a262016-08-19 15:54:22 +03002331 float x = unionArrays[0][i].getFConst();
2332 float y = unionArrays[1][i].getFConst();
2333 // Results are undefined if x < 0.
2334 // Results are undefined if x = 0 and y <= 0.
2335 if (x < 0.0f)
2336 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2337 &resultArray[i]);
2338 else if (x == 0.0f && y <= 0.0f)
2339 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2340 &resultArray[i]);
2341 else
2342 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302343 }
Olli Etuahof119a262016-08-19 15:54:22 +03002344 break;
Arun Patolebf790422015-05-18 17:53:04 +05302345 }
Arun Patolebf790422015-05-18 17:53:04 +05302346
Olli Etuahof119a262016-08-19 15:54:22 +03002347 case EOpMod:
Arun Patolebf790422015-05-18 17:53:04 +05302348 {
Olli Etuahof119a262016-08-19 15:54:22 +03002349 ASSERT(basicType == EbtFloat);
2350 resultArray = new TConstantUnion[maxObjectSize];
2351 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302352 {
Olli Etuahof119a262016-08-19 15:54:22 +03002353 float x = unionArrays[0][i].getFConst();
2354 float y = unionArrays[1][i].getFConst();
2355 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302356 }
Olli Etuahof119a262016-08-19 15:54:22 +03002357 break;
Arun Patolebf790422015-05-18 17:53:04 +05302358 }
Arun Patolebf790422015-05-18 17:53:04 +05302359
Olli Etuahof119a262016-08-19 15:54:22 +03002360 case EOpMin:
Arun Patole274f0702015-05-05 13:33:30 +05302361 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002362 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302363 for (size_t i = 0; i < maxObjectSize; i++)
2364 {
2365 switch (basicType)
2366 {
Olli Etuahof119a262016-08-19 15:54:22 +03002367 case EbtFloat:
2368 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
2369 unionArrays[1][i].getFConst()));
2370 break;
2371 case EbtInt:
2372 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
2373 unionArrays[1][i].getIConst()));
2374 break;
2375 case EbtUInt:
2376 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
2377 unionArrays[1][i].getUConst()));
2378 break;
2379 default:
2380 UNREACHABLE();
2381 break;
Arun Patole274f0702015-05-05 13:33:30 +05302382 }
2383 }
Olli Etuahof119a262016-08-19 15:54:22 +03002384 break;
Arun Patole274f0702015-05-05 13:33:30 +05302385 }
Arun Patole274f0702015-05-05 13:33:30 +05302386
Olli Etuahof119a262016-08-19 15:54:22 +03002387 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302388 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002389 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302390 for (size_t i = 0; i < maxObjectSize; i++)
2391 {
2392 switch (basicType)
2393 {
Olli Etuahof119a262016-08-19 15:54:22 +03002394 case EbtFloat:
2395 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
2396 unionArrays[1][i].getFConst()));
2397 break;
2398 case EbtInt:
2399 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
2400 unionArrays[1][i].getIConst()));
2401 break;
2402 case EbtUInt:
2403 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
2404 unionArrays[1][i].getUConst()));
2405 break;
2406 default:
2407 UNREACHABLE();
2408 break;
Arun Patole274f0702015-05-05 13:33:30 +05302409 }
2410 }
Olli Etuahof119a262016-08-19 15:54:22 +03002411 break;
Arun Patole274f0702015-05-05 13:33:30 +05302412 }
Arun Patole274f0702015-05-05 13:33:30 +05302413
Olli Etuahof119a262016-08-19 15:54:22 +03002414 case EOpStep:
Arun Patolebf790422015-05-18 17:53:04 +05302415 {
Olli Etuahof119a262016-08-19 15:54:22 +03002416 ASSERT(basicType == EbtFloat);
2417 resultArray = new TConstantUnion[maxObjectSize];
2418 for (size_t i = 0; i < maxObjectSize; i++)
2419 resultArray[i].setFConst(
2420 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
2421 : 1.0f);
2422 break;
Arun Patolebf790422015-05-18 17:53:04 +05302423 }
Arun Patolebf790422015-05-18 17:53:04 +05302424
Olli Etuahof119a262016-08-19 15:54:22 +03002425 case EOpLessThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302426 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002427 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302428 for (size_t i = 0; i < maxObjectSize; i++)
2429 {
2430 switch (basicType)
2431 {
Olli Etuahof119a262016-08-19 15:54:22 +03002432 case EbtFloat:
2433 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2434 unionArrays[1][i].getFConst());
2435 break;
2436 case EbtInt:
2437 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2438 unionArrays[1][i].getIConst());
2439 break;
2440 case EbtUInt:
2441 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2442 unionArrays[1][i].getUConst());
2443 break;
2444 default:
2445 UNREACHABLE();
2446 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302447 }
2448 }
Olli Etuahof119a262016-08-19 15:54:22 +03002449 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302450 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302451
Olli Etuahof119a262016-08-19 15:54:22 +03002452 case EOpLessThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302453 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002454 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302455 for (size_t i = 0; i < maxObjectSize; i++)
2456 {
2457 switch (basicType)
2458 {
Olli Etuahof119a262016-08-19 15:54:22 +03002459 case EbtFloat:
2460 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2461 unionArrays[1][i].getFConst());
2462 break;
2463 case EbtInt:
2464 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2465 unionArrays[1][i].getIConst());
2466 break;
2467 case EbtUInt:
2468 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2469 unionArrays[1][i].getUConst());
2470 break;
2471 default:
2472 UNREACHABLE();
2473 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302474 }
2475 }
Olli Etuahof119a262016-08-19 15:54:22 +03002476 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302477 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302478
Olli Etuahof119a262016-08-19 15:54:22 +03002479 case EOpGreaterThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302480 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002481 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302482 for (size_t i = 0; i < maxObjectSize; i++)
2483 {
2484 switch (basicType)
2485 {
Olli Etuahof119a262016-08-19 15:54:22 +03002486 case EbtFloat:
2487 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2488 unionArrays[1][i].getFConst());
2489 break;
2490 case EbtInt:
2491 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2492 unionArrays[1][i].getIConst());
2493 break;
2494 case EbtUInt:
2495 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2496 unionArrays[1][i].getUConst());
2497 break;
2498 default:
2499 UNREACHABLE();
2500 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002501 }
2502 }
Olli Etuahof119a262016-08-19 15:54:22 +03002503 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302504 }
Olli Etuahof119a262016-08-19 15:54:22 +03002505 case EOpGreaterThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302506 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002507 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302508 for (size_t i = 0; i < maxObjectSize; i++)
2509 {
2510 switch (basicType)
2511 {
Olli Etuahof119a262016-08-19 15:54:22 +03002512 case EbtFloat:
2513 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2514 unionArrays[1][i].getFConst());
2515 break;
2516 case EbtInt:
2517 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2518 unionArrays[1][i].getIConst());
2519 break;
2520 case EbtUInt:
2521 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2522 unionArrays[1][i].getUConst());
2523 break;
2524 default:
2525 UNREACHABLE();
2526 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302527 }
2528 }
2529 }
2530 break;
2531
Olli Etuahof119a262016-08-19 15:54:22 +03002532 case EOpVectorEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302533 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002534 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302535 for (size_t i = 0; i < maxObjectSize; i++)
2536 {
2537 switch (basicType)
2538 {
Olli Etuahof119a262016-08-19 15:54:22 +03002539 case EbtFloat:
2540 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2541 unionArrays[1][i].getFConst());
2542 break;
2543 case EbtInt:
2544 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2545 unionArrays[1][i].getIConst());
2546 break;
2547 case EbtUInt:
2548 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2549 unionArrays[1][i].getUConst());
2550 break;
2551 case EbtBool:
2552 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2553 unionArrays[1][i].getBConst());
2554 break;
2555 default:
2556 UNREACHABLE();
2557 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302558 }
2559 }
Olli Etuahof119a262016-08-19 15:54:22 +03002560 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302561 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302562
Olli Etuahof119a262016-08-19 15:54:22 +03002563 case EOpVectorNotEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302564 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002565 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302566 for (size_t i = 0; i < maxObjectSize; i++)
2567 {
2568 switch (basicType)
2569 {
Olli Etuahof119a262016-08-19 15:54:22 +03002570 case EbtFloat:
2571 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2572 unionArrays[1][i].getFConst());
2573 break;
2574 case EbtInt:
2575 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2576 unionArrays[1][i].getIConst());
2577 break;
2578 case EbtUInt:
2579 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2580 unionArrays[1][i].getUConst());
2581 break;
2582 case EbtBool:
2583 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2584 unionArrays[1][i].getBConst());
2585 break;
2586 default:
2587 UNREACHABLE();
2588 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302589 }
2590 }
Olli Etuahof119a262016-08-19 15:54:22 +03002591 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302592 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302593
Olli Etuahof119a262016-08-19 15:54:22 +03002594 case EOpDistance:
Arun Patole1155ddd2015-06-05 18:04:36 +05302595 {
Olli Etuahof119a262016-08-19 15:54:22 +03002596 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302597 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002598 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302599 for (size_t i = 0; i < maxObjectSize; i++)
2600 {
2601 float x = unionArrays[0][i].getFConst();
2602 float y = unionArrays[1][i].getFConst();
2603 distanceArray[i].setFConst(x - y);
2604 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002605 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Olli Etuahof119a262016-08-19 15:54:22 +03002606 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302607 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302608
Olli Etuahof119a262016-08-19 15:54:22 +03002609 case EOpDot:
2610 ASSERT(basicType == EbtFloat);
Olli Etuahob43846e2015-06-02 18:18:57 +03002611 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002612 resultArray->setFConst(
2613 VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2614 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302615
Olli Etuahof119a262016-08-19 15:54:22 +03002616 case EOpCross:
Arun Patole1155ddd2015-06-05 18:04:36 +05302617 {
Olli Etuahof119a262016-08-19 15:54:22 +03002618 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
Olli Etuahob43846e2015-06-02 18:18:57 +03002619 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002620 float x0 = unionArrays[0][0].getFConst();
2621 float x1 = unionArrays[0][1].getFConst();
2622 float x2 = unionArrays[0][2].getFConst();
2623 float y0 = unionArrays[1][0].getFConst();
2624 float y1 = unionArrays[1][1].getFConst();
2625 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002626 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2627 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2628 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Olli Etuahof119a262016-08-19 15:54:22 +03002629 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302630 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302631
Olli Etuahof119a262016-08-19 15:54:22 +03002632 case EOpReflect:
Arun Patole1155ddd2015-06-05 18:04:36 +05302633 {
Olli Etuahof119a262016-08-19 15:54:22 +03002634 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302635 // genType reflect (genType I, genType N) :
Olli Etuahof119a262016-08-19 15:54:22 +03002636 // For the incident vector I and surface orientation N, returns the reflection
2637 // direction:
Arun Patole1155ddd2015-06-05 18:04:36 +05302638 // I - 2 * dot(N, I) * N.
Olli Etuahof119a262016-08-19 15:54:22 +03002639 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302640 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2641 for (size_t i = 0; i < maxObjectSize; i++)
2642 {
2643 float result = unionArrays[0][i].getFConst() -
2644 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002645 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302646 }
Olli Etuahof119a262016-08-19 15:54:22 +03002647 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302648 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302649
Olli Etuahof119a262016-08-19 15:54:22 +03002650 case EOpMul:
Arun Patole7fa33552015-06-10 15:15:18 +05302651 {
Olli Etuahof119a262016-08-19 15:54:22 +03002652 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2653 (*sequence)[1]->getAsTyped()->isMatrix());
Arun Patole7fa33552015-06-10 15:15:18 +05302654 // Perform component-wise matrix multiplication.
2655 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002656 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302657 angle::Matrix<float> result =
2658 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2659 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002660 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302661 }
Arun Patole7fa33552015-06-10 15:15:18 +05302662
Olli Etuahof119a262016-08-19 15:54:22 +03002663 case EOpOuterProduct:
Arun Patole7fa33552015-06-10 15:15:18 +05302664 {
Olli Etuahof119a262016-08-19 15:54:22 +03002665 ASSERT(basicType == EbtFloat);
Arun Patole7fa33552015-06-10 15:15:18 +05302666 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2667 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuahof119a262016-08-19 15:54:22 +03002668 resultArray = new TConstantUnion[numRows * numCols];
Arun Patole7fa33552015-06-10 15:15:18 +05302669 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002670 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2671 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302672 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002673 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302674 }
Arun Patole7fa33552015-06-10 15:15:18 +05302675
Olli Etuahof119a262016-08-19 15:54:22 +03002676 default:
2677 UNREACHABLE();
2678 // TODO: Add constant folding support for other built-in operations that take 2
2679 // parameters and not handled above.
2680 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302681 }
2682 }
2683 else if (paramsCount == 3)
2684 {
2685 //
2686 // Ternary built-in
2687 //
2688 switch (op)
2689 {
Olli Etuahof119a262016-08-19 15:54:22 +03002690 case EOpClamp:
Arun Patole274f0702015-05-05 13:33:30 +05302691 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002692 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302693 for (size_t i = 0; i < maxObjectSize; i++)
2694 {
2695 switch (basicType)
2696 {
Olli Etuahof119a262016-08-19 15:54:22 +03002697 case EbtFloat:
Arun Patole274f0702015-05-05 13:33:30 +05302698 {
Olli Etuahof119a262016-08-19 15:54:22 +03002699 float x = unionArrays[0][i].getFConst();
Arun Patole274f0702015-05-05 13:33:30 +05302700 float min = unionArrays[1][i].getFConst();
2701 float max = unionArrays[2][i].getFConst();
2702 // Results are undefined if min > max.
2703 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002704 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2705 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302706 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002707 resultArray[i].setFConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002708 break;
Arun Patole274f0702015-05-05 13:33:30 +05302709 }
Olli Etuahof119a262016-08-19 15:54:22 +03002710
2711 case EbtInt:
Arun Patole274f0702015-05-05 13:33:30 +05302712 {
Olli Etuahof119a262016-08-19 15:54:22 +03002713 int x = unionArrays[0][i].getIConst();
Arun Patole274f0702015-05-05 13:33:30 +05302714 int min = unionArrays[1][i].getIConst();
2715 int max = unionArrays[2][i].getIConst();
2716 // Results are undefined if min > max.
2717 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002718 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2719 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302720 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002721 resultArray[i].setIConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002722 break;
Arun Patole274f0702015-05-05 13:33:30 +05302723 }
Olli Etuahof119a262016-08-19 15:54:22 +03002724 case EbtUInt:
Arun Patole274f0702015-05-05 13:33:30 +05302725 {
Olli Etuahof119a262016-08-19 15:54:22 +03002726 unsigned int x = unionArrays[0][i].getUConst();
Arun Patole274f0702015-05-05 13:33:30 +05302727 unsigned int min = unionArrays[1][i].getUConst();
2728 unsigned int max = unionArrays[2][i].getUConst();
2729 // Results are undefined if min > max.
2730 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002731 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2732 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302733 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002734 resultArray[i].setUConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002735 break;
Arun Patole274f0702015-05-05 13:33:30 +05302736 }
Olli Etuahof119a262016-08-19 15:54:22 +03002737 default:
2738 UNREACHABLE();
2739 break;
Arun Patole274f0702015-05-05 13:33:30 +05302740 }
2741 }
Olli Etuahof119a262016-08-19 15:54:22 +03002742 break;
Arun Patole274f0702015-05-05 13:33:30 +05302743 }
Arun Patole274f0702015-05-05 13:33:30 +05302744
Olli Etuahof119a262016-08-19 15:54:22 +03002745 case EOpMix:
Arun Patolebf790422015-05-18 17:53:04 +05302746 {
Olli Etuahof119a262016-08-19 15:54:22 +03002747 ASSERT(basicType == EbtFloat);
2748 resultArray = new TConstantUnion[maxObjectSize];
2749 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302750 {
Olli Etuahof119a262016-08-19 15:54:22 +03002751 float x = unionArrays[0][i].getFConst();
2752 float y = unionArrays[1][i].getFConst();
2753 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2754 if (type == EbtFloat)
Arun Patolebf790422015-05-18 17:53:04 +05302755 {
Olli Etuahof119a262016-08-19 15:54:22 +03002756 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2757 float a = unionArrays[2][i].getFConst();
2758 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2759 }
2760 else // 3rd parameter is EbtBool
2761 {
2762 ASSERT(type == EbtBool);
2763 // Selects which vector each returned component comes from.
2764 // For a component of a that is false, the corresponding component of x is
2765 // returned.
2766 // For a component of a that is true, the corresponding component of y is
2767 // returned.
2768 bool a = unionArrays[2][i].getBConst();
2769 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302770 }
2771 }
Olli Etuahof119a262016-08-19 15:54:22 +03002772 break;
Arun Patolebf790422015-05-18 17:53:04 +05302773 }
Arun Patolebf790422015-05-18 17:53:04 +05302774
Olli Etuahof119a262016-08-19 15:54:22 +03002775 case EOpSmoothStep:
Arun Patolebf790422015-05-18 17:53:04 +05302776 {
Olli Etuahof119a262016-08-19 15:54:22 +03002777 ASSERT(basicType == EbtFloat);
2778 resultArray = new TConstantUnion[maxObjectSize];
2779 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302780 {
Olli Etuahof119a262016-08-19 15:54:22 +03002781 float edge0 = unionArrays[0][i].getFConst();
2782 float edge1 = unionArrays[1][i].getFConst();
2783 float x = unionArrays[2][i].getFConst();
2784 // Results are undefined if edge0 >= edge1.
2785 if (edge0 >= edge1)
Arun Patolebf790422015-05-18 17:53:04 +05302786 {
Olli Etuahof119a262016-08-19 15:54:22 +03002787 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2788 &resultArray[i]);
2789 }
2790 else
2791 {
2792 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2793 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2794 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2795 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302796 }
2797 }
Olli Etuahof119a262016-08-19 15:54:22 +03002798 break;
Arun Patolebf790422015-05-18 17:53:04 +05302799 }
Arun Patolebf790422015-05-18 17:53:04 +05302800
Olli Etuahof119a262016-08-19 15:54:22 +03002801 case EOpFaceForward:
Arun Patole1155ddd2015-06-05 18:04:36 +05302802 {
Olli Etuahof119a262016-08-19 15:54:22 +03002803 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302804 // genType faceforward(genType N, genType I, genType Nref) :
2805 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahof119a262016-08-19 15:54:22 +03002806 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302807 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2808 for (size_t i = 0; i < maxObjectSize; i++)
2809 {
2810 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002811 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302812 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002813 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302814 }
Olli Etuahof119a262016-08-19 15:54:22 +03002815 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302816 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302817
Olli Etuahof119a262016-08-19 15:54:22 +03002818 case EOpRefract:
Arun Patole1155ddd2015-06-05 18:04:36 +05302819 {
Olli Etuahof119a262016-08-19 15:54:22 +03002820 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302821 // genType refract(genType I, genType N, float eta) :
Olli Etuahof119a262016-08-19 15:54:22 +03002822 // For the incident vector I and surface normal N, and the ratio of indices of
2823 // refraction eta,
Arun Patole1155ddd2015-06-05 18:04:36 +05302824 // return the refraction vector. The result is computed by
2825 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2826 // if (k < 0.0)
2827 // return genType(0.0)
2828 // else
2829 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahof119a262016-08-19 15:54:22 +03002830 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302831 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2832 for (size_t i = 0; i < maxObjectSize; i++)
2833 {
2834 float eta = unionArrays[2][i].getFConst();
Olli Etuahof119a262016-08-19 15:54:22 +03002835 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
Arun Patole1155ddd2015-06-05 18:04:36 +05302836 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002837 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302838 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002839 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Olli Etuahof119a262016-08-19 15:54:22 +03002840 (eta * dotProduct + sqrtf(k)) *
2841 unionArrays[1][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302842 }
Olli Etuahof119a262016-08-19 15:54:22 +03002843 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302844 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302845
Olli Etuahof119a262016-08-19 15:54:22 +03002846 default:
2847 UNREACHABLE();
2848 // TODO: Add constant folding support for other built-in operations that take 3
2849 // parameters and not handled above.
2850 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302851 }
2852 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002853 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302854}
2855
2856// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002857TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2858{
2859 if (hashFunction == NULL || name.empty())
2860 return name;
2861 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2862 TStringStream stream;
2863 stream << HASHED_NAME_PREFIX << std::hex << number;
2864 TString hashedName = stream.str();
2865 return hashedName;
2866}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002867
2868void TIntermTraverser::updateTree()
2869{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002870 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2871 {
2872 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2873 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002874 if (!insertion.insertionsAfter.empty())
2875 {
2876 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2877 insertion.insertionsAfter);
2878 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002879 }
2880 if (!insertion.insertionsBefore.empty())
2881 {
2882 bool inserted =
2883 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2884 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002885 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002886 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002887 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2888 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002889 const NodeUpdateEntry &replacement = mReplacements[ii];
2890 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002891 bool replaced =
2892 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002893 ASSERT(replaced);
2894
Olli Etuahocd94ef92015-04-16 19:18:10 +03002895 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002896 {
2897 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002898 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002899 // be replaced, we need to make sure we don't update the replaced
2900 // node; instead, we update the replacement node.
2901 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2902 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002903 NodeUpdateEntry &replacement2 = mReplacements[jj];
2904 if (replacement2.parent == replacement.original)
2905 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002906 }
2907 }
2908 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002909 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2910 {
2911 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2912 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002913 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
2914 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002915 ASSERT(replaced);
2916 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002917
Jamie Madill03d863c2016-07-27 18:15:53 -04002918 clearReplacementQueue();
2919}
2920
2921void TIntermTraverser::clearReplacementQueue()
2922{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002923 mReplacements.clear();
2924 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002925 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002926}
Jamie Madill1048e432016-07-23 18:51:28 -04002927
Jamie Madill03d863c2016-07-27 18:15:53 -04002928void TIntermTraverser::queueReplacement(TIntermNode *original,
2929 TIntermNode *replacement,
2930 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002931{
Jamie Madill03d863c2016-07-27 18:15:53 -04002932 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002933}
2934
Jamie Madill03d863c2016-07-27 18:15:53 -04002935void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2936 TIntermNode *original,
2937 TIntermNode *replacement,
2938 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002939{
Jamie Madill03d863c2016-07-27 18:15:53 -04002940 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2941 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002942}
Jamie Madill45bcc782016-11-07 13:58:48 -05002943
2944} // namespace sh