blob: cbdca7660c3e72602ed1928b05863c3e12bc01e8 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040021#include "compiler/translator/HashNames.h"
22#include "compiler/translator/IntermNode.h"
23#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040024#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040025
Jamie Madill45bcc782016-11-07 13:58:48 -050026namespace sh
27{
28
Jamie Madillb1a85f42014-08-19 15:23:24 -040029namespace
30{
31
Jamie Madilld7b1ab52016-12-12 14:42:19 -050032const float kPi = 3.14159265358979323846f;
Arun Patole9dea48f2015-04-02 11:45:09 +053033const float kDegreesToRadiansMultiplier = kPi / 180.0f;
34const float kRadiansToDegreesMultiplier = 180.0f / kPi;
35
Jamie Madillb1a85f42014-08-19 15:23:24 -040036TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
37{
38 return left > right ? left : right;
39}
40
Arun Patole274f0702015-05-05 13:33:30 +053041TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
42{
43 TConstantUnion *constUnion = new TConstantUnion[size];
44 for (unsigned int i = 0; i < size; ++i)
Jamie Madilld7b1ab52016-12-12 14:42:19 -050045 constUnion[i] = constant;
Arun Patole274f0702015-05-05 13:33:30 +053046
47 return constUnion;
48}
49
Olli Etuahof119a262016-08-19 15:54:22 +030050void UndefinedConstantFoldingError(const TSourceLoc &loc,
51 TOperator op,
52 TBasicType basicType,
53 TDiagnostics *diagnostics,
54 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053055{
Olli Etuahof119a262016-08-19 15:54:22 +030056 diagnostics->warning(loc, "operation result is undefined for the values passed in",
Olli Etuaho4de340a2016-12-16 09:32:03 +000057 GetOperatorString(op));
Arun Patolebf790422015-05-18 17:53:04 +053058
59 switch (basicType)
60 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050061 case EbtFloat:
62 result->setFConst(0.0f);
63 break;
64 case EbtInt:
65 result->setIConst(0);
66 break;
67 case EbtUInt:
68 result->setUConst(0u);
69 break;
70 case EbtBool:
71 result->setBConst(false);
72 break;
73 default:
74 break;
Arun Patolebf790422015-05-18 17:53:04 +053075 }
76}
77
Olli Etuaho5c0e0232015-11-11 15:55:59 +020078float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053079{
80 float result = 0.0f;
81 for (size_t i = 0; i < paramArraySize; i++)
82 {
83 float f = paramArray[i].getFConst();
84 result += f * f;
85 }
86 return sqrtf(result);
87}
88
Olli Etuaho5c0e0232015-11-11 15:55:59 +020089float VectorDotProduct(const TConstantUnion *paramArray1,
90 const TConstantUnion *paramArray2,
91 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053092{
93 float result = 0.0f;
94 for (size_t i = 0; i < paramArraySize; i++)
95 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
96 return result;
97}
98
Olli Etuaho3272a6d2016-08-29 17:54:50 +030099TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200100 const TIntermTyped *originalNode,
101 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300102{
103 if (constArray == nullptr)
104 {
105 return nullptr;
106 }
107 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200108 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300109 folded->setLine(originalNode->getLine());
110 return folded;
111}
112
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200113angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
114 const unsigned int &rows,
115 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530116{
117 std::vector<float> elements;
118 for (size_t i = 0; i < rows * cols; i++)
119 elements.push_back(paramArray[i].getFConst());
120 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300121 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
122 // so that the created matrix will have the expected dimensions after the transpose.
123 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530124}
125
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200126angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530127{
128 std::vector<float> elements;
129 for (size_t i = 0; i < size * size; i++)
130 elements.push_back(paramArray[i].getFConst());
131 // Transpose is used since the Matrix constructor expects arguments in row-major order,
132 // whereas the paramArray is in column-major order.
133 return angle::Matrix<float>(elements, size).transpose();
134}
135
136void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
137{
138 // Transpose is used since the input Matrix is in row-major order,
139 // whereas the actual result should be in column-major order.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500140 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530141 std::vector<float> resultElements = result.elements();
142 for (size_t i = 0; i < resultElements.size(); i++)
143 resultArray[i].setFConst(resultElements[i]);
144}
145
Jamie Madillb1a85f42014-08-19 15:23:24 -0400146} // namespace anonymous
147
Jamie Madillb1a85f42014-08-19 15:23:24 -0400148////////////////////////////////////////////////////////////////
149//
150// Member functions of the nodes used for building the tree.
151//
152////////////////////////////////////////////////////////////////
153
Olli Etuahod2a67b92014-10-21 16:42:57 +0300154void TIntermTyped::setTypePreservePrecision(const TType &t)
155{
156 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500157 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300158 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
159 mType.setPrecision(precision);
160}
161
Jamie Madillb1a85f42014-08-19 15:23:24 -0400162#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500163 if (node == original) \
164 { \
165 node = static_cast<type *>(replacement); \
166 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400167 }
168
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500169bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400170{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300171 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400172 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
173 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
174 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100175 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400176 return false;
177}
178
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500179bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400180{
181 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
182 return false;
183}
184
Olli Etuahob6fa0432016-09-28 16:28:05 +0100185bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
186{
187 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
188 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
189 return false;
190}
191
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500192bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400193{
194 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
195 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
196 return false;
197}
198
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500199bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400200{
Olli Etuahoa2234302016-08-31 12:05:39 +0300201 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400202 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
203 return false;
204}
205
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000206bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
207{
208 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
209 return false;
210}
211
Olli Etuaho336b1472016-10-05 16:37:55 +0100212bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
213{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000214 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100215 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
216 return false;
217}
218
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500219bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400220{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100221 return replaceChildNodeInternal(original, replacement);
222}
223
224bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
225{
226 return replaceChildNodeInternal(original, replacement);
227}
228
Olli Etuaho16c745a2017-01-16 17:02:27 +0000229bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
230{
231 return replaceChildNodeInternal(original, replacement);
232}
233
Olli Etuaho13389b62016-10-16 11:48:18 +0100234bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
235{
236 return replaceChildNodeInternal(original, replacement);
237}
238
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100239bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
240{
241 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400242 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100243 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400244 }
245 return false;
246}
247
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100248bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
249 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300250{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100251 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300252 {
253 if (*it == original)
254 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100255 it = getSequence()->erase(it);
256 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300257 return true;
258 }
259 }
260 return false;
261}
262
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100263bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
264 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300265{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100266 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300267 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300268 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300269 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100270 auto it = getSequence()->begin() + position;
271 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300272 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300273}
274
Olli Etuahofe486322017-03-21 09:30:54 +0000275TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
276 TIntermSequence *arguments)
277{
278 TIntermAggregate *callNode =
279 new TIntermAggregate(func.getReturnType(), EOpCallFunctionInAST, arguments);
280 callNode->getFunctionSymbolInfo()->setFromFunction(func);
281 return callNode;
282}
283
284TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TType &type,
285 const TSymbolUniqueId &id,
286 const TName &name,
287 TIntermSequence *arguments)
288{
289 TIntermAggregate *callNode = new TIntermAggregate(type, EOpCallFunctionInAST, arguments);
290 callNode->getFunctionSymbolInfo()->setId(id);
291 callNode->getFunctionSymbolInfo()->setNameObj(name);
292 return callNode;
293}
294
295TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
296 TIntermSequence *arguments)
297{
298 TIntermAggregate *callNode =
299 new TIntermAggregate(func.getReturnType(), EOpCallBuiltInFunction, arguments);
300 callNode->getFunctionSymbolInfo()->setFromFunction(func);
301 // Note that name needs to be set before texture function type is determined.
302 callNode->setBuiltInFunctionPrecision();
303 return callNode;
304}
305
306TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000307 TIntermSequence *arguments)
308{
Olli Etuahoa7ecec32017-05-08 17:43:55 +0300309 TIntermAggregate *constructorNode =
310 new TIntermAggregate(type, sh::TypeToConstructorOperator(type), arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000311 ASSERT(constructorNode->isConstructor());
312 return constructorNode;
313}
314
315TIntermAggregate *TIntermAggregate::Create(const TType &type,
316 TOperator op,
317 TIntermSequence *arguments)
318{
319 TIntermAggregate *node = new TIntermAggregate(type, op, arguments);
320 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
321 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
322 ASSERT(!node->isConstructor()); // Should use CreateConstructor
323 return node;
324}
325
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800326TIntermAggregate::TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments)
327 : TIntermOperator(op), mUseEmulatedFunction(false), mGotPrecisionFromChildren(false)
328{
329 if (arguments != nullptr)
330 {
331 mArguments.swap(*arguments);
332 }
333 setTypePrecisionAndQualifier(type);
334}
335
336void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
337{
338 setType(type);
339 mType.setQualifier(EvqTemporary);
340 if (!isFunctionCall())
341 {
342 if (isConstructor())
343 {
344 // Structs should not be precision qualified, the individual members may be.
345 // Built-in types on the other hand should be precision qualified.
346 if (mOp != EOpConstructStruct)
347 {
348 setPrecisionFromChildren();
349 }
350 }
351 else
352 {
353 setPrecisionForBuiltInOp();
354 }
355 if (areChildrenConstQualified())
356 {
357 mType.setQualifier(EvqConst);
358 }
359 }
360}
361
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200362bool TIntermAggregate::areChildrenConstQualified()
363{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800364 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200365 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800366 TIntermTyped *typedArg = arg->getAsTyped();
367 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200368 {
369 return false;
370 }
371 }
372 return true;
373}
374
Olli Etuahod2a67b92014-10-21 16:42:57 +0300375void TIntermAggregate::setPrecisionFromChildren()
376{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300377 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300378 if (getBasicType() == EbtBool)
379 {
380 mType.setPrecision(EbpUndefined);
381 return;
382 }
383
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500384 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800385 TIntermSequence::iterator childIter = mArguments.begin();
386 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300387 {
388 TIntermTyped *typed = (*childIter)->getAsTyped();
389 if (typed)
390 precision = GetHigherPrecision(typed->getPrecision(), precision);
391 ++childIter;
392 }
393 mType.setPrecision(precision);
394}
395
Olli Etuaho9250cb22017-01-21 10:51:27 +0000396void TIntermAggregate::setPrecisionForBuiltInOp()
397{
398 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800399 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000400 if (!setPrecisionForSpecialBuiltInOp())
401 {
402 setPrecisionFromChildren();
403 }
404}
405
406bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
407{
408 switch (mOp)
409 {
410 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800411 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
412 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000413 return true;
414 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800415 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
416 mArguments[1]->getAsTyped()->getPrecision()));
417 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000418 return true;
419 case EOpUaddCarry:
420 case EOpUsubBorrow:
421 mType.setPrecision(EbpHigh);
422 return true;
423 default:
424 return false;
425 }
426}
427
Olli Etuahod2a67b92014-10-21 16:42:57 +0300428void TIntermAggregate::setBuiltInFunctionPrecision()
429{
430 // All built-ins returning bool should be handled as ops, not functions.
431 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800432 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300433
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800434 TPrecision precision = EbpUndefined;
435 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300436 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800437 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300438 // ESSL spec section 8: texture functions get their precision from the sampler.
439 if (typed && IsSampler(typed->getBasicType()))
440 {
441 precision = typed->getPrecision();
442 break;
443 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300444 }
445 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
446 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100447 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300448 mType.setPrecision(EbpHigh);
449 else
450 mType.setPrecision(precision);
451}
452
Olli Etuahof2209f72017-04-01 12:45:55 +0300453TString TIntermAggregate::getSymbolTableMangledName() const
454{
455 ASSERT(!isConstructor());
456 switch (mOp)
457 {
458 case EOpCallInternalRawFunction:
459 case EOpCallBuiltInFunction:
460 case EOpCallFunctionInAST:
461 return TFunction::GetMangledNameFromCall(mFunctionInfo.getName(), mArguments);
462 default:
463 TString opString = GetOperatorString(mOp);
464 return TFunction::GetMangledNameFromCall(opString, mArguments);
465 }
466}
467
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100468void TIntermBlock::appendStatement(TIntermNode *statement)
469{
Olli Etuaho13389b62016-10-16 11:48:18 +0100470 // Declaration nodes with no children can appear if all the declarators just added constants to
471 // the symbol table instead of generating code. They're no-ops so they aren't added to blocks.
472 if (statement != nullptr && (statement->getAsDeclarationNode() == nullptr ||
473 !statement->getAsDeclarationNode()->getSequence()->empty()))
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100474 {
475 mStatements.push_back(statement);
476 }
477}
478
Olli Etuaho16c745a2017-01-16 17:02:27 +0000479void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
480{
481 ASSERT(parameter != nullptr);
482 mParameters.push_back(parameter);
483}
484
Olli Etuaho13389b62016-10-16 11:48:18 +0100485void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
486{
487 ASSERT(declarator != nullptr);
488 ASSERT(declarator->getAsSymbolNode() != nullptr ||
489 (declarator->getAsBinaryNode() != nullptr &&
490 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
491 ASSERT(mDeclarators.empty() ||
492 declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType()));
493 mDeclarators.push_back(declarator);
494}
495
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300496bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
497{
498 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
499 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
500 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
501 return false;
502}
503
Olli Etuaho57961272016-09-14 13:57:46 +0300504bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400505{
506 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100507 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
508 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400509 return false;
510}
511
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500512bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200513{
514 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100515 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200516 return false;
517}
518
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500519bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200520{
521 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
522 return false;
523}
524
Olli Etuahod7a25242015-08-18 13:49:45 +0300525TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
526{
527 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
528 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
529 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
530 mLine = node.mLine;
531}
532
Olli Etuahod4f4c112016-04-15 15:11:24 +0300533bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
534{
535 TIntermAggregate *constructor = getAsAggregate();
536 if (!constructor || !constructor->isConstructor())
537 {
538 return false;
539 }
540 for (TIntermNode *&node : *constructor->getSequence())
541 {
542 if (!node->getAsConstantUnion())
543 return false;
544 }
545 return true;
546}
547
Corentin Wallez509e4562016-08-25 14:55:44 -0400548// static
549TIntermTyped *TIntermTyped::CreateIndexNode(int index)
550{
551 TConstantUnion *u = new TConstantUnion[1];
552 u[0].setIConst(index);
553
554 TType type(EbtInt, EbpUndefined, EvqConst, 1);
555 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
556 return node;
557}
558
559// static
560TIntermTyped *TIntermTyped::CreateZero(const TType &type)
561{
562 TType constType(type);
563 constType.setQualifier(EvqConst);
564
565 if (!type.isArray() && type.getBasicType() != EbtStruct)
566 {
Corentin Wallez509e4562016-08-25 14:55:44 -0400567 size_t size = constType.getObjectSize();
568 TConstantUnion *u = new TConstantUnion[size];
569 for (size_t i = 0; i < size; ++i)
570 {
571 switch (type.getBasicType())
572 {
573 case EbtFloat:
574 u[i].setFConst(0.0f);
575 break;
576 case EbtInt:
577 u[i].setIConst(0);
578 break;
579 case EbtUInt:
580 u[i].setUConst(0u);
581 break;
582 case EbtBool:
583 u[i].setBConst(false);
584 break;
585 default:
Corentin Wallez17a5c062017-01-22 15:20:53 -0500586 // CreateZero is called by ParseContext that keeps parsing even when an error
587 // occurs, so it is possible for CreateZero to be called with non-basic types.
588 // This happens only on error condition but CreateZero needs to return a value
589 // with the correct type to continue the typecheck. That's why we handle
590 // non-basic type by setting whatever value, we just need the type to be right.
591 u[i].setIConst(42);
592 break;
Corentin Wallez509e4562016-08-25 14:55:44 -0400593 }
594 }
595
596 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
597 return node;
598 }
599
Olli Etuaho193c0952017-05-02 15:51:47 +0300600 if (type.getBasicType() == EbtVoid)
601 {
602 // Void array. This happens only on error condition, similarly to the case above. We don't
603 // have a constructor operator for void, so this needs special handling. We'll end up with a
604 // value without the array type, but that should not be a problem.
605 constType.clearArrayness();
606 return CreateZero(constType);
607 }
608
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800609 TIntermSequence *arguments = new TIntermSequence();
Corentin Wallez509e4562016-08-25 14:55:44 -0400610
611 if (type.isArray())
612 {
613 TType elementType(type);
614 elementType.clearArrayness();
615
616 size_t arraySize = type.getArraySize();
617 for (size_t i = 0; i < arraySize; ++i)
618 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800619 arguments->push_back(CreateZero(elementType));
Corentin Wallez509e4562016-08-25 14:55:44 -0400620 }
621 }
622 else
623 {
624 ASSERT(type.getBasicType() == EbtStruct);
625
626 TStructure *structure = type.getStruct();
627 for (const auto &field : structure->fields())
628 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800629 arguments->push_back(CreateZero(*field->type()));
Corentin Wallez509e4562016-08-25 14:55:44 -0400630 }
631 }
632
Olli Etuahoa7ecec32017-05-08 17:43:55 +0300633 return TIntermAggregate::CreateConstructor(constType, arguments);
Corentin Wallez509e4562016-08-25 14:55:44 -0400634}
635
Corentin Wallez36fd1002016-12-08 11:30:44 -0500636// static
637TIntermTyped *TIntermTyped::CreateBool(bool value)
638{
639 TConstantUnion *u = new TConstantUnion[1];
640 u[0].setBConst(value);
641
642 TType type(EbtBool, EbpUndefined, EvqConst, 1);
643 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
644 return node;
645}
646
Olli Etuahod7a25242015-08-18 13:49:45 +0300647TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
648{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200649 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300650}
651
Olli Etuahobd674552016-10-06 13:28:42 +0100652void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
653{
Olli Etuahoec9232b2017-03-27 17:01:37 +0300654 setName(function.getName());
Olli Etuahofe486322017-03-21 09:30:54 +0000655 setId(TSymbolUniqueId(function));
656}
657
658TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id) : mId(new TSymbolUniqueId(id))
659{
660}
661
662TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
663 : mName(info.mName), mId(nullptr)
664{
665 if (info.mId)
666 {
667 mId = new TSymbolUniqueId(*info.mId);
668 }
669}
670
671TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
672{
673 mName = info.mName;
674 if (info.mId)
675 {
676 mId = new TSymbolUniqueId(*info.mId);
677 }
678 else
679 {
680 mId = nullptr;
681 }
682 return *this;
683}
684
685void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
686{
687 mId = new TSymbolUniqueId(id);
688}
689
690const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
691{
692 ASSERT(mId);
693 return *mId;
Olli Etuahobd674552016-10-06 13:28:42 +0100694}
695
Olli Etuahod7a25242015-08-18 13:49:45 +0300696TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
697 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300698 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100699 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
700 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300701{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800702 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300703 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800704 TIntermTyped *typedArg = arg->getAsTyped();
705 ASSERT(typedArg != nullptr);
706 TIntermTyped *argCopy = typedArg->deepCopy();
707 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300708 }
709}
710
Olli Etuahofe486322017-03-21 09:30:54 +0000711TIntermAggregate *TIntermAggregate::shallowCopy() const
712{
713 TIntermSequence *copySeq = new TIntermSequence();
714 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
715 TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq);
716 *copyNode->getFunctionSymbolInfo() = mFunctionInfo;
717 copyNode->setLine(mLine);
718 return copyNode;
719}
720
Olli Etuahob6fa0432016-09-28 16:28:05 +0100721TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
722{
723 TIntermTyped *operandCopy = node.mOperand->deepCopy();
724 ASSERT(operandCopy != nullptr);
725 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000726 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100727}
728
Olli Etuahod7a25242015-08-18 13:49:45 +0300729TIntermBinary::TIntermBinary(const TIntermBinary &node)
730 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
731{
732 TIntermTyped *leftCopy = node.mLeft->deepCopy();
733 TIntermTyped *rightCopy = node.mRight->deepCopy();
734 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
735 mLeft = leftCopy;
736 mRight = rightCopy;
737}
738
739TIntermUnary::TIntermUnary(const TIntermUnary &node)
740 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
741{
742 TIntermTyped *operandCopy = node.mOperand->deepCopy();
743 ASSERT(operandCopy != nullptr);
744 mOperand = operandCopy;
745}
746
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300747TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300748{
Olli Etuahod7a25242015-08-18 13:49:45 +0300749 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300750 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
751 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300752 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300753 mCondition = conditionCopy;
754 mTrueExpression = trueCopy;
755 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300756}
757
Jamie Madillb1a85f42014-08-19 15:23:24 -0400758bool TIntermOperator::isAssignment() const
759{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300760 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400761}
762
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300763bool TIntermOperator::isMultiplication() const
764{
765 switch (mOp)
766 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500767 case EOpMul:
768 case EOpMatrixTimesMatrix:
769 case EOpMatrixTimesVector:
770 case EOpMatrixTimesScalar:
771 case EOpVectorTimesMatrix:
772 case EOpVectorTimesScalar:
773 return true;
774 default:
775 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300776 }
777}
778
Olli Etuahoa7ecec32017-05-08 17:43:55 +0300779// Returns true if the operator is for one of the constructors.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400780bool TIntermOperator::isConstructor() const
781{
782 switch (mOp)
783 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500784 case EOpConstructVec2:
785 case EOpConstructVec3:
786 case EOpConstructVec4:
787 case EOpConstructMat2:
788 case EOpConstructMat2x3:
789 case EOpConstructMat2x4:
790 case EOpConstructMat3x2:
791 case EOpConstructMat3:
792 case EOpConstructMat3x4:
793 case EOpConstructMat4x2:
794 case EOpConstructMat4x3:
795 case EOpConstructMat4:
796 case EOpConstructFloat:
797 case EOpConstructIVec2:
798 case EOpConstructIVec3:
799 case EOpConstructIVec4:
800 case EOpConstructInt:
801 case EOpConstructUVec2:
802 case EOpConstructUVec3:
803 case EOpConstructUVec4:
804 case EOpConstructUInt:
805 case EOpConstructBVec2:
806 case EOpConstructBVec3:
807 case EOpConstructBVec4:
808 case EOpConstructBool:
809 case EOpConstructStruct:
810 return true;
811 default:
Olli Etuahoa7ecec32017-05-08 17:43:55 +0300812 // EOpConstruct is not supposed to be used in the AST.
813 ASSERT(mOp != EOpConstruct);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500814 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400815 }
816}
817
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800818bool TIntermOperator::isFunctionCall() const
819{
820 switch (mOp)
821 {
822 case EOpCallFunctionInAST:
823 case EOpCallBuiltInFunction:
824 case EOpCallInternalRawFunction:
825 return true;
826 default:
827 return false;
828 }
829}
830
Olli Etuaho1dded802016-08-18 18:13:13 +0300831TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
832{
833 if (left.isMatrix())
834 {
835 if (right.isMatrix())
836 {
837 return EOpMatrixTimesMatrix;
838 }
839 else
840 {
841 if (right.isVector())
842 {
843 return EOpMatrixTimesVector;
844 }
845 else
846 {
847 return EOpMatrixTimesScalar;
848 }
849 }
850 }
851 else
852 {
853 if (right.isMatrix())
854 {
855 if (left.isVector())
856 {
857 return EOpVectorTimesMatrix;
858 }
859 else
860 {
861 return EOpMatrixTimesScalar;
862 }
863 }
864 else
865 {
866 // Neither operand is a matrix.
867 if (left.isVector() == right.isVector())
868 {
869 // Leave as component product.
870 return EOpMul;
871 }
872 else
873 {
874 return EOpVectorTimesScalar;
875 }
876 }
877 }
878}
879
880TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
881{
882 if (left.isMatrix())
883 {
884 if (right.isMatrix())
885 {
886 return EOpMatrixTimesMatrixAssign;
887 }
888 else
889 {
890 // right should be scalar, but this may not be validated yet.
891 return EOpMatrixTimesScalarAssign;
892 }
893 }
894 else
895 {
896 if (right.isMatrix())
897 {
898 // Left should be a vector, but this may not be validated yet.
899 return EOpVectorTimesMatrixAssign;
900 }
901 else
902 {
903 // Neither operand is a matrix.
904 if (left.isVector() == right.isVector())
905 {
906 // Leave as component product.
907 return EOpMulAssign;
908 }
909 else
910 {
911 // left should be vector and right should be scalar, but this may not be validated
912 // yet.
913 return EOpVectorTimesScalarAssign;
914 }
915 }
916 }
917}
918
Jamie Madillb1a85f42014-08-19 15:23:24 -0400919//
920// Make sure the type of a unary operator is appropriate for its
921// combination of operation and operand type.
922//
Olli Etuahoa2234302016-08-31 12:05:39 +0300923void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400924{
Olli Etuahoa2234302016-08-31 12:05:39 +0300925 TQualifier resultQualifier = EvqTemporary;
926 if (mOperand->getQualifier() == EvqConst)
927 resultQualifier = EvqConst;
928
929 unsigned char operandPrimarySize =
930 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400931 switch (mOp)
932 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300933 case EOpFloatBitsToInt:
934 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
935 break;
936 case EOpFloatBitsToUint:
937 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
938 break;
939 case EOpIntBitsToFloat:
940 case EOpUintBitsToFloat:
941 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
942 break;
943 case EOpPackSnorm2x16:
944 case EOpPackUnorm2x16:
945 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800946 case EOpPackUnorm4x8:
947 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300948 setType(TType(EbtUInt, EbpHigh, resultQualifier));
949 break;
950 case EOpUnpackSnorm2x16:
951 case EOpUnpackUnorm2x16:
952 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
953 break;
954 case EOpUnpackHalf2x16:
955 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
956 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800957 case EOpUnpackUnorm4x8:
958 case EOpUnpackSnorm4x8:
959 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
960 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300961 case EOpAny:
962 case EOpAll:
963 setType(TType(EbtBool, EbpUndefined, resultQualifier));
964 break;
965 case EOpLength:
966 case EOpDeterminant:
967 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
968 break;
969 case EOpTranspose:
970 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
971 static_cast<unsigned char>(mOperand->getType().getRows()),
972 static_cast<unsigned char>(mOperand->getType().getCols())));
973 break;
974 case EOpIsInf:
975 case EOpIsNan:
976 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
977 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000978 case EOpBitfieldReverse:
979 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
980 break;
981 case EOpBitCount:
982 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
983 break;
984 case EOpFindLSB:
985 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
986 break;
987 case EOpFindMSB:
988 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
989 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300990 default:
991 setType(mOperand->getType());
992 mType.setQualifier(resultQualifier);
993 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400994 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300995}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400996
Olli Etuahob6fa0432016-09-28 16:28:05 +0100997TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
998 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
999 mOperand(operand),
1000 mSwizzleOffsets(swizzleOffsets)
1001{
1002 ASSERT(mSwizzleOffsets.size() <= 4);
1003 promote();
1004}
1005
Olli Etuahoa2234302016-08-31 12:05:39 +03001006TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
1007 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
1008{
1009 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001010}
1011
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001012TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1013 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
1014{
1015 promote();
1016}
1017
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001018TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1019 : TIntermNode(), mSymbol(symbol)
1020{
1021 ASSERT(symbol);
1022 setLine(line);
1023}
1024
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001025TIntermTernary::TIntermTernary(TIntermTyped *cond,
1026 TIntermTyped *trueExpression,
1027 TIntermTyped *falseExpression)
1028 : TIntermTyped(trueExpression->getType()),
1029 mCondition(cond),
1030 mTrueExpression(trueExpression),
1031 mFalseExpression(falseExpression)
1032{
1033 getTypePointer()->setQualifier(
1034 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1035}
1036
Olli Etuaho81629262017-04-19 11:56:01 +03001037TIntermLoop::TIntermLoop(TLoopType type,
1038 TIntermNode *init,
1039 TIntermTyped *cond,
1040 TIntermTyped *expr,
1041 TIntermBlock *body)
1042 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1043{
1044 // Declaration nodes with no children can appear if all the declarators just added constants to
1045 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1046 if (mInit && mInit->getAsDeclarationNode() &&
1047 mInit->getAsDeclarationNode()->getSequence()->empty())
1048 {
1049 mInit = nullptr;
1050 }
1051}
1052
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001053// static
1054TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1055 TIntermTyped *trueExpression,
1056 TIntermTyped *falseExpression)
1057{
1058 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1059 falseExpression->getQualifier() == EvqConst)
1060 {
1061 return EvqConst;
1062 }
1063 return EvqTemporary;
1064}
1065
Olli Etuahob6fa0432016-09-28 16:28:05 +01001066void TIntermSwizzle::promote()
1067{
1068 TQualifier resultQualifier = EvqTemporary;
1069 if (mOperand->getQualifier() == EvqConst)
1070 resultQualifier = EvqConst;
1071
1072 auto numFields = mSwizzleOffsets.size();
1073 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1074 static_cast<unsigned char>(numFields)));
1075}
1076
1077bool TIntermSwizzle::hasDuplicateOffsets() const
1078{
1079 int offsetCount[4] = {0u, 0u, 0u, 0u};
1080 for (const auto offset : mSwizzleOffsets)
1081 {
1082 offsetCount[offset]++;
1083 if (offsetCount[offset] > 1)
1084 {
1085 return true;
1086 }
1087 }
1088 return false;
1089}
1090
Olli Etuaho09b04a22016-12-15 13:30:26 +00001091bool TIntermSwizzle::offsetsMatch(int offset) const
1092{
1093 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1094}
1095
Olli Etuahob6fa0432016-09-28 16:28:05 +01001096void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1097{
1098 for (const int offset : mSwizzleOffsets)
1099 {
1100 switch (offset)
1101 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001102 case 0:
1103 *out << "x";
1104 break;
1105 case 1:
1106 *out << "y";
1107 break;
1108 case 2:
1109 *out << "z";
1110 break;
1111 case 3:
1112 *out << "w";
1113 break;
1114 default:
1115 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001116 }
1117 }
1118}
1119
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001120TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1121 const TIntermTyped *left,
1122 const TIntermTyped *right)
1123{
1124 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1125 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1126 right->getQualifier() != EvqConst)
1127 {
1128 return EvqTemporary;
1129 }
1130 return EvqConst;
1131}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001132
1133// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001134void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001135{
Olli Etuaho1dded802016-08-18 18:13:13 +03001136 ASSERT(!isMultiplication() ||
1137 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1138
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001139 // Comma is handled as a special case.
1140 if (mOp == EOpComma)
1141 {
1142 setType(mRight->getType());
1143 return;
1144 }
1145
Jamie Madillb1a85f42014-08-19 15:23:24 -04001146 // Base assumption: just make the type the same as the left
1147 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001148 setType(mLeft->getType());
1149
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001150 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001151 // Binary operations results in temporary variables unless both
1152 // operands are const.
1153 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1154 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001155 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001156 getTypePointer()->setQualifier(EvqTemporary);
1157 }
1158
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001159 // Handle indexing ops.
1160 switch (mOp)
1161 {
1162 case EOpIndexDirect:
1163 case EOpIndexIndirect:
1164 if (mLeft->isArray())
1165 {
1166 mType.clearArrayness();
1167 }
1168 else if (mLeft->isMatrix())
1169 {
1170 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1171 static_cast<unsigned char>(mLeft->getRows())));
1172 }
1173 else if (mLeft->isVector())
1174 {
1175 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1176 }
1177 else
1178 {
1179 UNREACHABLE();
1180 }
1181 return;
1182 case EOpIndexDirectStruct:
1183 {
1184 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1185 const int i = mRight->getAsConstantUnion()->getIConst(0);
1186 setType(*fields[i]->type());
1187 getTypePointer()->setQualifier(resultQualifier);
1188 return;
1189 }
1190 case EOpIndexDirectInterfaceBlock:
1191 {
1192 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1193 const int i = mRight->getAsConstantUnion()->getIConst(0);
1194 setType(*fields[i]->type());
1195 getTypePointer()->setQualifier(resultQualifier);
1196 return;
1197 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001198 default:
1199 break;
1200 }
1201
1202 ASSERT(mLeft->isArray() == mRight->isArray());
1203
1204 // The result gets promoted to the highest precision.
1205 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1206 getTypePointer()->setPrecision(higherPrecision);
1207
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001208 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001209
1210 //
1211 // All scalars or structs. Code after this test assumes this case is removed!
1212 //
1213 if (nominalSize == 1)
1214 {
1215 switch (mOp)
1216 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001217 //
1218 // Promote to conditional
1219 //
1220 case EOpEqual:
1221 case EOpNotEqual:
1222 case EOpLessThan:
1223 case EOpGreaterThan:
1224 case EOpLessThanEqual:
1225 case EOpGreaterThanEqual:
1226 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1227 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001228
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001229 //
1230 // And and Or operate on conditionals
1231 //
1232 case EOpLogicalAnd:
1233 case EOpLogicalXor:
1234 case EOpLogicalOr:
1235 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1236 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1237 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001238
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001239 default:
1240 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001241 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001242 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001243 }
1244
1245 // If we reach here, at least one of the operands is vector or matrix.
1246 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001247 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001248
Jamie Madillb1a85f42014-08-19 15:23:24 -04001249 switch (mOp)
1250 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001251 case EOpMul:
1252 break;
1253 case EOpMatrixTimesScalar:
1254 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001255 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001256 setType(TType(basicType, higherPrecision, resultQualifier,
1257 static_cast<unsigned char>(mRight->getCols()),
1258 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001259 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001260 break;
1261 case EOpMatrixTimesVector:
1262 setType(TType(basicType, higherPrecision, resultQualifier,
1263 static_cast<unsigned char>(mLeft->getRows()), 1));
1264 break;
1265 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001266 setType(TType(basicType, higherPrecision, resultQualifier,
1267 static_cast<unsigned char>(mRight->getCols()),
1268 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001269 break;
1270 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001271 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001272 static_cast<unsigned char>(nominalSize), 1));
1273 break;
1274 case EOpVectorTimesMatrix:
1275 setType(TType(basicType, higherPrecision, resultQualifier,
1276 static_cast<unsigned char>(mRight->getCols()), 1));
1277 break;
1278 case EOpMulAssign:
1279 case EOpVectorTimesScalarAssign:
1280 case EOpVectorTimesMatrixAssign:
1281 case EOpMatrixTimesScalarAssign:
1282 case EOpMatrixTimesMatrixAssign:
1283 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1284 break;
1285 case EOpAssign:
1286 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001287 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1288 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1289 break;
1290 case EOpAdd:
1291 case EOpSub:
1292 case EOpDiv:
1293 case EOpIMod:
1294 case EOpBitShiftLeft:
1295 case EOpBitShiftRight:
1296 case EOpBitwiseAnd:
1297 case EOpBitwiseXor:
1298 case EOpBitwiseOr:
1299 case EOpAddAssign:
1300 case EOpSubAssign:
1301 case EOpDivAssign:
1302 case EOpIModAssign:
1303 case EOpBitShiftLeftAssign:
1304 case EOpBitShiftRightAssign:
1305 case EOpBitwiseAndAssign:
1306 case EOpBitwiseXorAssign:
1307 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001308 {
1309 const int secondarySize =
1310 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1311 setType(TType(basicType, higherPrecision, resultQualifier,
1312 static_cast<unsigned char>(nominalSize),
1313 static_cast<unsigned char>(secondarySize)));
1314 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001315 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001316 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001317 case EOpEqual:
1318 case EOpNotEqual:
1319 case EOpLessThan:
1320 case EOpGreaterThan:
1321 case EOpLessThanEqual:
1322 case EOpGreaterThanEqual:
1323 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1324 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001325 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001326 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001327
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001328 case EOpIndexDirect:
1329 case EOpIndexIndirect:
1330 case EOpIndexDirectInterfaceBlock:
1331 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001332 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001333 UNREACHABLE();
1334 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001335 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001336 UNREACHABLE();
1337 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001338 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001339}
1340
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001341const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001342{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001343 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001344 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001345 ASSERT(index < static_cast<int>(getType().getArraySize()));
1346 TType arrayElementType = getType();
1347 arrayElementType.clearArrayness();
1348 size_t arrayElementSize = arrayElementType.getObjectSize();
1349 return &mUnionArrayPointer[arrayElementSize * index];
1350 }
1351 else if (isMatrix())
1352 {
1353 ASSERT(index < getType().getCols());
1354 int size = getType().getRows();
1355 return &mUnionArrayPointer[size * index];
1356 }
1357 else if (isVector())
1358 {
1359 ASSERT(index < getType().getNominalSize());
1360 return &mUnionArrayPointer[index];
1361 }
1362 else
1363 {
1364 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001365 return nullptr;
1366 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001367}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001368
Olli Etuahob6fa0432016-09-28 16:28:05 +01001369TIntermTyped *TIntermSwizzle::fold()
1370{
1371 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1372 if (operandConstant == nullptr)
1373 {
1374 return nullptr;
1375 }
1376
1377 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1378 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1379 {
1380 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1381 }
1382 return CreateFoldedNode(constArray, this, mType.getQualifier());
1383}
1384
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001385TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1386{
1387 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1388 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1389 switch (mOp)
1390 {
1391 case EOpIndexDirect:
1392 {
1393 if (leftConstant == nullptr || rightConstant == nullptr)
1394 {
1395 return nullptr;
1396 }
1397 int index = rightConstant->getIConst(0);
1398
1399 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1400 return CreateFoldedNode(constArray, this, mType.getQualifier());
1401 }
1402 case EOpIndexDirectStruct:
1403 {
1404 if (leftConstant == nullptr || rightConstant == nullptr)
1405 {
1406 return nullptr;
1407 }
1408 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1409 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1410
1411 size_t previousFieldsSize = 0;
1412 for (size_t i = 0; i < index; ++i)
1413 {
1414 previousFieldsSize += fields[i]->type()->getObjectSize();
1415 }
1416
1417 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1418 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1419 }
1420 case EOpIndexIndirect:
1421 case EOpIndexDirectInterfaceBlock:
1422 // Can never be constant folded.
1423 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001424 default:
1425 {
1426 if (leftConstant == nullptr || rightConstant == nullptr)
1427 {
1428 return nullptr;
1429 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001430 TConstantUnion *constArray =
1431 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001432
1433 // Nodes may be constant folded without being qualified as constant.
1434 return CreateFoldedNode(constArray, this, mType.getQualifier());
1435 }
1436 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001437}
1438
Olli Etuahof119a262016-08-19 15:54:22 +03001439TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001440{
1441 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1442 if (operandConstant == nullptr)
1443 {
1444 return nullptr;
1445 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301446
1447 TConstantUnion *constArray = nullptr;
1448 switch (mOp)
1449 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001450 case EOpAny:
1451 case EOpAll:
1452 case EOpLength:
1453 case EOpTranspose:
1454 case EOpDeterminant:
1455 case EOpInverse:
1456 case EOpPackSnorm2x16:
1457 case EOpUnpackSnorm2x16:
1458 case EOpPackUnorm2x16:
1459 case EOpUnpackUnorm2x16:
1460 case EOpPackHalf2x16:
1461 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001462 case EOpPackUnorm4x8:
1463 case EOpPackSnorm4x8:
1464 case EOpUnpackUnorm4x8:
1465 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001466 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1467 break;
1468 default:
1469 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1470 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301471 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001472
1473 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001474 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001475}
1476
Olli Etuahof119a262016-08-19 15:54:22 +03001477TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001478{
1479 // Make sure that all params are constant before actual constant folding.
1480 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001481 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001482 if (param->getAsConstantUnion() == nullptr)
1483 {
1484 return nullptr;
1485 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001486 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001487 TConstantUnion *constArray = nullptr;
1488 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001489 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001490 else
Olli Etuahof119a262016-08-19 15:54:22 +03001491 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001492
1493 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001494 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001495}
1496
Jamie Madillb1a85f42014-08-19 15:23:24 -04001497//
1498// The fold functions see if an operation on a constant can be done in place,
1499// without generating run-time code.
1500//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001501// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001502//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001503TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1504 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001505 TDiagnostics *diagnostics,
1506 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001507{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001508 const TConstantUnion *leftArray = getUnionArrayPointer();
1509 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001510
Olli Etuahof119a262016-08-19 15:54:22 +03001511 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001512
1513 size_t objectSize = getType().getObjectSize();
1514
1515 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1516 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1517 {
1518 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1519 }
1520 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1521 {
1522 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001523 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001524 objectSize = rightNode->getType().getObjectSize();
1525 }
1526
1527 TConstantUnion *resultArray = nullptr;
1528
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001529 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001530 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001531 case EOpAdd:
1532 resultArray = new TConstantUnion[objectSize];
1533 for (size_t i = 0; i < objectSize; i++)
1534 resultArray[i] =
1535 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1536 break;
1537 case EOpSub:
1538 resultArray = new TConstantUnion[objectSize];
1539 for (size_t i = 0; i < objectSize; i++)
1540 resultArray[i] =
1541 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1542 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001543
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001544 case EOpMul:
1545 case EOpVectorTimesScalar:
1546 case EOpMatrixTimesScalar:
1547 resultArray = new TConstantUnion[objectSize];
1548 for (size_t i = 0; i < objectSize; i++)
1549 resultArray[i] =
1550 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1551 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001552
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001553 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001554 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001555 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001556 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001557
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001558 const int leftCols = getCols();
1559 const int leftRows = getRows();
1560 const int rightCols = rightNode->getType().getCols();
1561 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001562 const int resultCols = rightCols;
1563 const int resultRows = leftRows;
1564
1565 resultArray = new TConstantUnion[resultCols * resultRows];
1566 for (int row = 0; row < resultRows; row++)
1567 {
1568 for (int column = 0; column < resultCols; column++)
1569 {
1570 resultArray[resultRows * column + row].setFConst(0.0f);
1571 for (int i = 0; i < leftCols; i++)
1572 {
1573 resultArray[resultRows * column + row].setFConst(
1574 resultArray[resultRows * column + row].getFConst() +
1575 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001576 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001577 }
1578 }
1579 }
1580 }
1581 break;
1582
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001583 case EOpDiv:
1584 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001585 {
1586 resultArray = new TConstantUnion[objectSize];
1587 for (size_t i = 0; i < objectSize; i++)
1588 {
1589 switch (getType().getBasicType())
1590 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001591 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001592 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001593 ASSERT(op == EOpDiv);
1594 float dividend = leftArray[i].getFConst();
1595 float divisor = rightArray[i].getFConst();
1596 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001597 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001598 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001599 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001600 diagnostics->warning(
1601 getLine(),
1602 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001603 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001604 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001605 }
1606 else
1607 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001608 diagnostics->warning(getLine(),
1609 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001610 bool negativeResult =
1611 std::signbit(dividend) != std::signbit(divisor);
1612 resultArray[i].setFConst(
1613 negativeResult ? -std::numeric_limits<float>::infinity()
1614 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001615 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001616 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001617 else if (gl::isInf(dividend) && gl::isInf(divisor))
1618 {
1619 diagnostics->warning(getLine(),
1620 "Infinity divided by infinity during constant "
1621 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001622 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001623 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1624 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001625 else
1626 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001627 float result = dividend / divisor;
1628 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001629 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001630 diagnostics->warning(
1631 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001632 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001633 }
1634 resultArray[i].setFConst(result);
1635 }
1636 break;
1637 }
1638 case EbtInt:
1639 if (rightArray[i] == 0)
1640 {
1641 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001642 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001643 resultArray[i].setIConst(INT_MAX);
1644 }
1645 else
1646 {
1647 int lhs = leftArray[i].getIConst();
1648 int divisor = rightArray[i].getIConst();
1649 if (op == EOpDiv)
1650 {
1651 // Check for the special case where the minimum representable number
1652 // is
1653 // divided by -1. If left alone this leads to integer overflow in
1654 // C++.
1655 // ESSL 3.00.6 section 4.1.3 Integers:
1656 // "However, for the case where the minimum representable value is
1657 // divided by -1, it is allowed to return either the minimum
1658 // representable value or the maximum representable value."
1659 if (lhs == -0x7fffffff - 1 && divisor == -1)
1660 {
1661 resultArray[i].setIConst(0x7fffffff);
1662 }
1663 else
1664 {
1665 resultArray[i].setIConst(lhs / divisor);
1666 }
Olli Etuahod4453572016-09-27 13:21:46 +01001667 }
1668 else
1669 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001670 ASSERT(op == EOpIMod);
1671 if (lhs < 0 || divisor < 0)
1672 {
1673 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1674 // when
1675 // either one of the operands is negative.
1676 diagnostics->warning(getLine(),
1677 "Negative modulus operator operand "
1678 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001679 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001680 resultArray[i].setIConst(0);
1681 }
1682 else
1683 {
1684 resultArray[i].setIConst(lhs % divisor);
1685 }
Olli Etuahod4453572016-09-27 13:21:46 +01001686 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001687 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001688 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001689
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001690 case EbtUInt:
1691 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001692 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001693 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001694 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001695 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001696 }
1697 else
1698 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001699 if (op == EOpDiv)
1700 {
1701 resultArray[i].setUConst(leftArray[i].getUConst() /
1702 rightArray[i].getUConst());
1703 }
1704 else
1705 {
1706 ASSERT(op == EOpIMod);
1707 resultArray[i].setUConst(leftArray[i].getUConst() %
1708 rightArray[i].getUConst());
1709 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001710 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001711 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001712
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001713 default:
1714 UNREACHABLE();
1715 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001716 }
1717 }
1718 }
1719 break;
1720
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001721 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001722 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001723 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001724 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001725
1726 const int matrixCols = getCols();
1727 const int matrixRows = getRows();
1728
1729 resultArray = new TConstantUnion[matrixRows];
1730
1731 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1732 {
1733 resultArray[matrixRow].setFConst(0.0f);
1734 for (int col = 0; col < matrixCols; col++)
1735 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001736 resultArray[matrixRow].setFConst(
1737 resultArray[matrixRow].getFConst() +
1738 leftArray[col * matrixRows + matrixRow].getFConst() *
1739 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001740 }
1741 }
1742 }
1743 break;
1744
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001745 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001746 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001747 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001748 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001749
1750 const int matrixCols = rightNode->getType().getCols();
1751 const int matrixRows = rightNode->getType().getRows();
1752
1753 resultArray = new TConstantUnion[matrixCols];
1754
1755 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1756 {
1757 resultArray[matrixCol].setFConst(0.0f);
1758 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1759 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001760 resultArray[matrixCol].setFConst(
1761 resultArray[matrixCol].getFConst() +
1762 leftArray[matrixRow].getFConst() *
1763 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001764 }
1765 }
1766 }
1767 break;
1768
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001769 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001770 {
1771 resultArray = new TConstantUnion[objectSize];
1772 for (size_t i = 0; i < objectSize; i++)
1773 {
1774 resultArray[i] = leftArray[i] && rightArray[i];
1775 }
1776 }
1777 break;
1778
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001779 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001780 {
1781 resultArray = new TConstantUnion[objectSize];
1782 for (size_t i = 0; i < objectSize; i++)
1783 {
1784 resultArray[i] = leftArray[i] || rightArray[i];
1785 }
1786 }
1787 break;
1788
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001789 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001790 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001791 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001792 resultArray = new TConstantUnion[objectSize];
1793 for (size_t i = 0; i < objectSize; i++)
1794 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001795 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001796 }
1797 }
1798 break;
1799
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001800 case EOpBitwiseAnd:
1801 resultArray = new TConstantUnion[objectSize];
1802 for (size_t i = 0; i < objectSize; i++)
1803 resultArray[i] = leftArray[i] & rightArray[i];
1804 break;
1805 case EOpBitwiseXor:
1806 resultArray = new TConstantUnion[objectSize];
1807 for (size_t i = 0; i < objectSize; i++)
1808 resultArray[i] = leftArray[i] ^ rightArray[i];
1809 break;
1810 case EOpBitwiseOr:
1811 resultArray = new TConstantUnion[objectSize];
1812 for (size_t i = 0; i < objectSize; i++)
1813 resultArray[i] = leftArray[i] | rightArray[i];
1814 break;
1815 case EOpBitShiftLeft:
1816 resultArray = new TConstantUnion[objectSize];
1817 for (size_t i = 0; i < objectSize; i++)
1818 resultArray[i] =
1819 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1820 break;
1821 case EOpBitShiftRight:
1822 resultArray = new TConstantUnion[objectSize];
1823 for (size_t i = 0; i < objectSize; i++)
1824 resultArray[i] =
1825 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1826 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001827
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001828 case EOpLessThan:
1829 ASSERT(objectSize == 1);
1830 resultArray = new TConstantUnion[1];
1831 resultArray->setBConst(*leftArray < *rightArray);
1832 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001833
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001834 case EOpGreaterThan:
1835 ASSERT(objectSize == 1);
1836 resultArray = new TConstantUnion[1];
1837 resultArray->setBConst(*leftArray > *rightArray);
1838 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001839
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001840 case EOpLessThanEqual:
1841 ASSERT(objectSize == 1);
1842 resultArray = new TConstantUnion[1];
1843 resultArray->setBConst(!(*leftArray > *rightArray));
1844 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001845
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001846 case EOpGreaterThanEqual:
1847 ASSERT(objectSize == 1);
1848 resultArray = new TConstantUnion[1];
1849 resultArray->setBConst(!(*leftArray < *rightArray));
1850 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001851
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001852 case EOpEqual:
1853 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001854 {
1855 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001856 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001857 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001858 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001859 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001860 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001861 equal = false;
1862 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001863 }
1864 }
1865 if (op == EOpEqual)
1866 {
1867 resultArray->setBConst(equal);
1868 }
1869 else
1870 {
1871 resultArray->setBConst(!equal);
1872 }
1873 }
1874 break;
1875
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001876 default:
1877 UNREACHABLE();
1878 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001879 }
1880 return resultArray;
1881}
1882
Olli Etuahof119a262016-08-19 15:54:22 +03001883// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1884// code. Returns the constant value to keep using. Nullptr should not be returned.
1885TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001886{
Olli Etuahof119a262016-08-19 15:54:22 +03001887 // Do operations where the return type may have a different number of components compared to the
1888 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001889
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001890 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001891 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301892
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001893 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301894 TConstantUnion *resultArray = nullptr;
1895 switch (op)
1896 {
Olli Etuahof119a262016-08-19 15:54:22 +03001897 case EOpAny:
1898 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301899 resultArray = new TConstantUnion();
1900 resultArray->setBConst(false);
1901 for (size_t i = 0; i < objectSize; i++)
1902 {
1903 if (operandArray[i].getBConst())
1904 {
1905 resultArray->setBConst(true);
1906 break;
1907 }
1908 }
1909 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301910
Olli Etuahof119a262016-08-19 15:54:22 +03001911 case EOpAll:
1912 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301913 resultArray = new TConstantUnion();
1914 resultArray->setBConst(true);
1915 for (size_t i = 0; i < objectSize; i++)
1916 {
1917 if (!operandArray[i].getBConst())
1918 {
1919 resultArray->setBConst(false);
1920 break;
1921 }
1922 }
1923 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301924
Olli Etuahof119a262016-08-19 15:54:22 +03001925 case EOpLength:
1926 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301927 resultArray = new TConstantUnion();
1928 resultArray->setFConst(VectorLength(operandArray, objectSize));
1929 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301930
Olli Etuahof119a262016-08-19 15:54:22 +03001931 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301932 {
Olli Etuahof119a262016-08-19 15:54:22 +03001933 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301934 resultArray = new TConstantUnion[objectSize];
1935 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001936 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301937 SetUnionArrayFromMatrix(result, resultArray);
1938 break;
1939 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301940
Olli Etuahof119a262016-08-19 15:54:22 +03001941 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301942 {
Olli Etuahof119a262016-08-19 15:54:22 +03001943 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301944 unsigned int size = getType().getNominalSize();
1945 ASSERT(size >= 2 && size <= 4);
1946 resultArray = new TConstantUnion();
1947 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1948 break;
1949 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301950
Olli Etuahof119a262016-08-19 15:54:22 +03001951 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301952 {
Olli Etuahof119a262016-08-19 15:54:22 +03001953 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301954 unsigned int size = getType().getNominalSize();
1955 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001956 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301957 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1958 SetUnionArrayFromMatrix(result, resultArray);
1959 break;
1960 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301961
Olli Etuahof119a262016-08-19 15:54:22 +03001962 case EOpPackSnorm2x16:
1963 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301964 ASSERT(getType().getNominalSize() == 2);
1965 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001966 resultArray->setUConst(
1967 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301968 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301969
Olli Etuahof119a262016-08-19 15:54:22 +03001970 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301971 {
Olli Etuahof119a262016-08-19 15:54:22 +03001972 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301973 resultArray = new TConstantUnion[2];
1974 float f1, f2;
1975 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1976 resultArray[0].setFConst(f1);
1977 resultArray[1].setFConst(f2);
1978 break;
1979 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301980
Olli Etuahof119a262016-08-19 15:54:22 +03001981 case EOpPackUnorm2x16:
1982 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301983 ASSERT(getType().getNominalSize() == 2);
1984 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001985 resultArray->setUConst(
1986 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301987 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301988
Olli Etuahof119a262016-08-19 15:54:22 +03001989 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301990 {
Olli Etuahof119a262016-08-19 15:54:22 +03001991 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301992 resultArray = new TConstantUnion[2];
1993 float f1, f2;
1994 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1995 resultArray[0].setFConst(f1);
1996 resultArray[1].setFConst(f2);
1997 break;
1998 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301999
Olli Etuahof119a262016-08-19 15:54:22 +03002000 case EOpPackHalf2x16:
2001 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302002 ASSERT(getType().getNominalSize() == 2);
2003 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002004 resultArray->setUConst(
2005 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302006 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302007
Olli Etuahof119a262016-08-19 15:54:22 +03002008 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302009 {
Olli Etuahof119a262016-08-19 15:54:22 +03002010 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302011 resultArray = new TConstantUnion[2];
2012 float f1, f2;
2013 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2014 resultArray[0].setFConst(f1);
2015 resultArray[1].setFConst(f2);
2016 break;
2017 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302018
Olli Etuaho25aef452017-01-29 16:15:44 -08002019 case EOpPackUnorm4x8:
2020 {
2021 ASSERT(getType().getBasicType() == EbtFloat);
2022 resultArray = new TConstantUnion();
2023 resultArray->setUConst(
2024 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2025 operandArray[2].getFConst(), operandArray[3].getFConst()));
2026 break;
2027 }
2028 case EOpPackSnorm4x8:
2029 {
2030 ASSERT(getType().getBasicType() == EbtFloat);
2031 resultArray = new TConstantUnion();
2032 resultArray->setUConst(
2033 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2034 operandArray[2].getFConst(), operandArray[3].getFConst()));
2035 break;
2036 }
2037 case EOpUnpackUnorm4x8:
2038 {
2039 ASSERT(getType().getBasicType() == EbtUInt);
2040 resultArray = new TConstantUnion[4];
2041 float f[4];
2042 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2043 for (size_t i = 0; i < 4; ++i)
2044 {
2045 resultArray[i].setFConst(f[i]);
2046 }
2047 break;
2048 }
2049 case EOpUnpackSnorm4x8:
2050 {
2051 ASSERT(getType().getBasicType() == EbtUInt);
2052 resultArray = new TConstantUnion[4];
2053 float f[4];
2054 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2055 for (size_t i = 0; i < 4; ++i)
2056 {
2057 resultArray[i].setFConst(f[i]);
2058 }
2059 break;
2060 }
2061
Olli Etuahof119a262016-08-19 15:54:22 +03002062 default:
2063 UNREACHABLE();
2064 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302065 }
2066
2067 return resultArray;
2068}
2069
Olli Etuahof119a262016-08-19 15:54:22 +03002070TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2071 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302072{
Olli Etuahof119a262016-08-19 15:54:22 +03002073 // Do unary operations where each component of the result is computed based on the corresponding
2074 // component of the operand. Also folds normalize, though the divisor in that case takes all
2075 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302076
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002077 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002078 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002079
2080 size_t objectSize = getType().getObjectSize();
2081
Arun Patoleab2b9a22015-07-06 18:27:56 +05302082 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2083 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302084 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002085 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302086 {
Olli Etuahof119a262016-08-19 15:54:22 +03002087 case EOpNegative:
2088 switch (getType().getBasicType())
2089 {
2090 case EbtFloat:
2091 resultArray[i].setFConst(-operandArray[i].getFConst());
2092 break;
2093 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002094 if (operandArray[i] == std::numeric_limits<int>::min())
2095 {
2096 // The minimum representable integer doesn't have a positive
2097 // counterpart, rather the negation overflows and in ESSL is supposed to
2098 // wrap back to the minimum representable integer. Make sure that we
2099 // don't actually let the negation overflow, which has undefined
2100 // behavior in C++.
2101 resultArray[i].setIConst(std::numeric_limits<int>::min());
2102 }
2103 else
2104 {
2105 resultArray[i].setIConst(-operandArray[i].getIConst());
2106 }
Olli Etuahof119a262016-08-19 15:54:22 +03002107 break;
2108 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002109 if (operandArray[i] == 0x80000000u)
2110 {
2111 resultArray[i].setUConst(0x80000000u);
2112 }
2113 else
2114 {
2115 resultArray[i].setUConst(static_cast<unsigned int>(
2116 -static_cast<int>(operandArray[i].getUConst())));
2117 }
Olli Etuahof119a262016-08-19 15:54:22 +03002118 break;
2119 default:
2120 UNREACHABLE();
2121 return nullptr;
2122 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302123 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302124
Olli Etuahof119a262016-08-19 15:54:22 +03002125 case EOpPositive:
2126 switch (getType().getBasicType())
2127 {
2128 case EbtFloat:
2129 resultArray[i].setFConst(operandArray[i].getFConst());
2130 break;
2131 case EbtInt:
2132 resultArray[i].setIConst(operandArray[i].getIConst());
2133 break;
2134 case EbtUInt:
2135 resultArray[i].setUConst(static_cast<unsigned int>(
2136 static_cast<int>(operandArray[i].getUConst())));
2137 break;
2138 default:
2139 UNREACHABLE();
2140 return nullptr;
2141 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302142 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302143
Olli Etuahof119a262016-08-19 15:54:22 +03002144 case EOpLogicalNot:
2145 switch (getType().getBasicType())
2146 {
2147 case EbtBool:
2148 resultArray[i].setBConst(!operandArray[i].getBConst());
2149 break;
2150 default:
2151 UNREACHABLE();
2152 return nullptr;
2153 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302154 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302155
Olli Etuahof119a262016-08-19 15:54:22 +03002156 case EOpBitwiseNot:
2157 switch (getType().getBasicType())
2158 {
2159 case EbtInt:
2160 resultArray[i].setIConst(~operandArray[i].getIConst());
2161 break;
2162 case EbtUInt:
2163 resultArray[i].setUConst(~operandArray[i].getUConst());
2164 break;
2165 default:
2166 UNREACHABLE();
2167 return nullptr;
2168 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302169 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302170
Olli Etuahof119a262016-08-19 15:54:22 +03002171 case EOpRadians:
2172 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302173 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2174 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302175
Olli Etuahof119a262016-08-19 15:54:22 +03002176 case EOpDegrees:
2177 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302178 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2179 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302180
Olli Etuahof119a262016-08-19 15:54:22 +03002181 case EOpSin:
2182 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302183 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302184
Olli Etuahof119a262016-08-19 15:54:22 +03002185 case EOpCos:
2186 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2187 break;
2188
2189 case EOpTan:
2190 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2191 break;
2192
2193 case EOpAsin:
2194 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2195 // 0.
2196 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2197 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2198 diagnostics, &resultArray[i]);
2199 else
2200 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2201 break;
2202
2203 case EOpAcos:
2204 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2205 // 0.
2206 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2207 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2208 diagnostics, &resultArray[i]);
2209 else
2210 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2211 break;
2212
2213 case EOpAtan:
2214 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2215 break;
2216
2217 case EOpSinh:
2218 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2219 break;
2220
2221 case EOpCosh:
2222 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2223 break;
2224
2225 case EOpTanh:
2226 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2227 break;
2228
2229 case EOpAsinh:
2230 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2231 break;
2232
2233 case EOpAcosh:
2234 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2235 if (operandArray[i].getFConst() < 1.0f)
2236 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2237 diagnostics, &resultArray[i]);
2238 else
2239 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2240 break;
2241
2242 case EOpAtanh:
2243 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2244 // 0.
2245 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2246 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2247 diagnostics, &resultArray[i]);
2248 else
2249 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2250 break;
2251
2252 case EOpAbs:
2253 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302254 {
Olli Etuahof119a262016-08-19 15:54:22 +03002255 case EbtFloat:
2256 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2257 break;
2258 case EbtInt:
2259 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2260 break;
2261 default:
2262 UNREACHABLE();
2263 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302264 }
2265 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002266
2267 case EOpSign:
2268 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302269 {
Olli Etuahof119a262016-08-19 15:54:22 +03002270 case EbtFloat:
2271 {
2272 float fConst = operandArray[i].getFConst();
2273 float fResult = 0.0f;
2274 if (fConst > 0.0f)
2275 fResult = 1.0f;
2276 else if (fConst < 0.0f)
2277 fResult = -1.0f;
2278 resultArray[i].setFConst(fResult);
2279 break;
2280 }
2281 case EbtInt:
2282 {
2283 int iConst = operandArray[i].getIConst();
2284 int iResult = 0;
2285 if (iConst > 0)
2286 iResult = 1;
2287 else if (iConst < 0)
2288 iResult = -1;
2289 resultArray[i].setIConst(iResult);
2290 break;
2291 }
2292 default:
2293 UNREACHABLE();
2294 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302295 }
2296 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302297
Olli Etuahof119a262016-08-19 15:54:22 +03002298 case EOpFloor:
2299 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2300 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302301
Olli Etuahof119a262016-08-19 15:54:22 +03002302 case EOpTrunc:
2303 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2304 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302305
Olli Etuahof119a262016-08-19 15:54:22 +03002306 case EOpRound:
2307 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2308 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302309
Olli Etuahof119a262016-08-19 15:54:22 +03002310 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302311 {
Olli Etuahof119a262016-08-19 15:54:22 +03002312 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302313 float x = operandArray[i].getFConst();
2314 float result;
2315 float fractPart = modff(x, &result);
2316 if (fabsf(fractPart) == 0.5f)
2317 result = 2.0f * roundf(x / 2.0f);
2318 else
2319 result = roundf(x);
2320 resultArray[i].setFConst(result);
2321 break;
2322 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302323
Olli Etuahof119a262016-08-19 15:54:22 +03002324 case EOpCeil:
2325 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2326 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302327
Olli Etuahof119a262016-08-19 15:54:22 +03002328 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302329 {
Olli Etuahof119a262016-08-19 15:54:22 +03002330 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302331 float x = operandArray[i].getFConst();
2332 resultArray[i].setFConst(x - floorf(x));
2333 break;
2334 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302335
Olli Etuahof119a262016-08-19 15:54:22 +03002336 case EOpIsNan:
2337 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302338 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2339 break;
Arun Patole551279e2015-07-07 18:18:23 +05302340
Olli Etuahof119a262016-08-19 15:54:22 +03002341 case EOpIsInf:
2342 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302343 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2344 break;
Arun Patole551279e2015-07-07 18:18:23 +05302345
Olli Etuahof119a262016-08-19 15:54:22 +03002346 case EOpFloatBitsToInt:
2347 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302348 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2349 break;
Arun Patole551279e2015-07-07 18:18:23 +05302350
Olli Etuahof119a262016-08-19 15:54:22 +03002351 case EOpFloatBitsToUint:
2352 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302353 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2354 break;
Arun Patole551279e2015-07-07 18:18:23 +05302355
Olli Etuahof119a262016-08-19 15:54:22 +03002356 case EOpIntBitsToFloat:
2357 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302358 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2359 break;
Arun Patole551279e2015-07-07 18:18:23 +05302360
Olli Etuahof119a262016-08-19 15:54:22 +03002361 case EOpUintBitsToFloat:
2362 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302363 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2364 break;
Arun Patole551279e2015-07-07 18:18:23 +05302365
Olli Etuahof119a262016-08-19 15:54:22 +03002366 case EOpExp:
2367 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2368 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302369
Olli Etuahof119a262016-08-19 15:54:22 +03002370 case EOpLog:
2371 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2372 if (operandArray[i].getFConst() <= 0.0f)
2373 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2374 diagnostics, &resultArray[i]);
2375 else
2376 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2377 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302378
Olli Etuahof119a262016-08-19 15:54:22 +03002379 case EOpExp2:
2380 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2381 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302382
Olli Etuahof119a262016-08-19 15:54:22 +03002383 case EOpLog2:
2384 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2385 // And log2f is not available on some plarforms like old android, so just using
2386 // log(x)/log(2) here.
2387 if (operandArray[i].getFConst() <= 0.0f)
2388 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2389 diagnostics, &resultArray[i]);
2390 else
2391 {
2392 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2393 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2394 }
2395 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302396
Olli Etuahof119a262016-08-19 15:54:22 +03002397 case EOpSqrt:
2398 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2399 if (operandArray[i].getFConst() < 0.0f)
2400 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2401 diagnostics, &resultArray[i]);
2402 else
2403 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2404 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302405
Olli Etuahof119a262016-08-19 15:54:22 +03002406 case EOpInverseSqrt:
2407 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2408 // so getting the square root first using builtin function sqrt() and then taking
2409 // its inverse.
2410 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2411 // result to 0.
2412 if (operandArray[i].getFConst() <= 0.0f)
2413 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2414 diagnostics, &resultArray[i]);
2415 else
2416 {
2417 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2418 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2419 }
2420 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302421
Olli Etuahod68924e2017-01-02 17:34:40 +00002422 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002423 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302424 resultArray[i].setBConst(!operandArray[i].getBConst());
2425 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302426
Olli Etuahof119a262016-08-19 15:54:22 +03002427 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302428 {
Olli Etuahof119a262016-08-19 15:54:22 +03002429 ASSERT(getType().getBasicType() == EbtFloat);
2430 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302431 float length = VectorLength(operandArray, objectSize);
2432 if (length)
2433 resultArray[i].setFConst(x / length);
2434 else
Olli Etuahof119a262016-08-19 15:54:22 +03002435 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2436 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302437 break;
2438 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002439 case EOpBitfieldReverse:
2440 {
2441 uint32_t value;
2442 if (getType().getBasicType() == EbtInt)
2443 {
2444 value = static_cast<uint32_t>(operandArray[i].getIConst());
2445 }
2446 else
2447 {
2448 ASSERT(getType().getBasicType() == EbtUInt);
2449 value = operandArray[i].getUConst();
2450 }
2451 uint32_t result = gl::BitfieldReverse(value);
2452 if (getType().getBasicType() == EbtInt)
2453 {
2454 resultArray[i].setIConst(static_cast<int32_t>(result));
2455 }
2456 else
2457 {
2458 resultArray[i].setUConst(result);
2459 }
2460 break;
2461 }
2462 case EOpBitCount:
2463 {
2464 uint32_t value;
2465 if (getType().getBasicType() == EbtInt)
2466 {
2467 value = static_cast<uint32_t>(operandArray[i].getIConst());
2468 }
2469 else
2470 {
2471 ASSERT(getType().getBasicType() == EbtUInt);
2472 value = operandArray[i].getUConst();
2473 }
2474 int result = gl::BitCount(value);
2475 resultArray[i].setIConst(result);
2476 break;
2477 }
2478 case EOpFindLSB:
2479 {
2480 uint32_t value;
2481 if (getType().getBasicType() == EbtInt)
2482 {
2483 value = static_cast<uint32_t>(operandArray[i].getIConst());
2484 }
2485 else
2486 {
2487 ASSERT(getType().getBasicType() == EbtUInt);
2488 value = operandArray[i].getUConst();
2489 }
2490 resultArray[i].setIConst(gl::FindLSB(value));
2491 break;
2492 }
2493 case EOpFindMSB:
2494 {
2495 uint32_t value;
2496 if (getType().getBasicType() == EbtInt)
2497 {
2498 int intValue = operandArray[i].getIConst();
2499 value = static_cast<uint32_t>(intValue);
2500 if (intValue < 0)
2501 {
2502 // Look for zero instead of one in value. This also handles the intValue ==
2503 // -1 special case, where the return value needs to be -1.
2504 value = ~value;
2505 }
2506 }
2507 else
2508 {
2509 ASSERT(getType().getBasicType() == EbtUInt);
2510 value = operandArray[i].getUConst();
2511 }
2512 resultArray[i].setIConst(gl::FindMSB(value));
2513 break;
2514 }
Olli Etuahof119a262016-08-19 15:54:22 +03002515 case EOpDFdx:
2516 case EOpDFdy:
2517 case EOpFwidth:
2518 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302519 // Derivatives of constant arguments should be 0.
2520 resultArray[i].setFConst(0.0f);
2521 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302522
Olli Etuahof119a262016-08-19 15:54:22 +03002523 default:
2524 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302525 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302526 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002527
Arun Patoleab2b9a22015-07-06 18:27:56 +05302528 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002529}
2530
Olli Etuahof119a262016-08-19 15:54:22 +03002531void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2532 FloatTypeUnaryFunc builtinFunc,
2533 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302534{
2535 ASSERT(builtinFunc);
2536
Olli Etuahof119a262016-08-19 15:54:22 +03002537 ASSERT(getType().getBasicType() == EbtFloat);
2538 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302539}
2540
Jamie Madillb1a85f42014-08-19 15:23:24 -04002541// static
Olli Etuahof119a262016-08-19 15:54:22 +03002542TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002543{
2544 ASSERT(aggregate->getSequence()->size() > 0u);
2545 size_t resultSize = aggregate->getType().getObjectSize();
2546 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2547 TBasicType basicType = aggregate->getBasicType();
2548
2549 size_t resultIndex = 0u;
2550
2551 if (aggregate->getSequence()->size() == 1u)
2552 {
2553 TIntermNode *argument = aggregate->getSequence()->front();
2554 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2555 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2556 // Check the special case of constructing a matrix diagonal from a single scalar,
2557 // or a vector from a single scalar.
2558 if (argumentConstant->getType().getObjectSize() == 1u)
2559 {
2560 if (aggregate->isMatrix())
2561 {
2562 int resultCols = aggregate->getType().getCols();
2563 int resultRows = aggregate->getType().getRows();
2564 for (int col = 0; col < resultCols; ++col)
2565 {
2566 for (int row = 0; row < resultRows; ++row)
2567 {
2568 if (col == row)
2569 {
2570 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2571 }
2572 else
2573 {
2574 resultArray[resultIndex].setFConst(0.0f);
2575 }
2576 ++resultIndex;
2577 }
2578 }
2579 }
2580 else
2581 {
2582 while (resultIndex < resultSize)
2583 {
2584 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2585 ++resultIndex;
2586 }
2587 }
2588 ASSERT(resultIndex == resultSize);
2589 return resultArray;
2590 }
2591 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2592 {
2593 // The special case of constructing a matrix from a matrix.
2594 int argumentCols = argumentConstant->getType().getCols();
2595 int argumentRows = argumentConstant->getType().getRows();
2596 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002597 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002598 for (int col = 0; col < resultCols; ++col)
2599 {
2600 for (int row = 0; row < resultRows; ++row)
2601 {
2602 if (col < argumentCols && row < argumentRows)
2603 {
2604 resultArray[resultIndex].cast(basicType,
2605 argumentUnionArray[col * argumentRows + row]);
2606 }
2607 else if (col == row)
2608 {
2609 resultArray[resultIndex].setFConst(1.0f);
2610 }
2611 else
2612 {
2613 resultArray[resultIndex].setFConst(0.0f);
2614 }
2615 ++resultIndex;
2616 }
2617 }
2618 ASSERT(resultIndex == resultSize);
2619 return resultArray;
2620 }
2621 }
2622
2623 for (TIntermNode *&argument : *aggregate->getSequence())
2624 {
2625 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2626 size_t argumentSize = argumentConstant->getType().getObjectSize();
2627 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2628 for (size_t i = 0u; i < argumentSize; ++i)
2629 {
2630 if (resultIndex >= resultSize)
2631 break;
2632 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2633 ++resultIndex;
2634 }
2635 }
2636 ASSERT(resultIndex == resultSize);
2637 return resultArray;
2638}
2639
2640// static
Olli Etuahof119a262016-08-19 15:54:22 +03002641TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2642 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302643{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002644 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002645 TIntermSequence *arguments = aggregate->getSequence();
2646 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2647 std::vector<const TConstantUnion *> unionArrays(argsCount);
2648 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002649 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302650 TBasicType basicType = EbtVoid;
2651 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002652 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302653 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002654 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2655 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302656
2657 if (i == 0)
2658 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002659 basicType = argConstant->getType().getBasicType();
2660 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302661 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002662 unionArrays[i] = argConstant->getUnionArrayPointer();
2663 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002664 if (objectSizes[i] > maxObjectSize)
2665 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302666 }
2667
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002668 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302669 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002670 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302671 if (objectSizes[i] != maxObjectSize)
2672 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2673 }
Arun Patole274f0702015-05-05 13:33:30 +05302674
Olli Etuahob43846e2015-06-02 18:18:57 +03002675 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002676
2677 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302678 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002679 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302680 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002681 ASSERT(basicType == EbtFloat);
2682 resultArray = new TConstantUnion[maxObjectSize];
2683 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302684 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002685 float y = unionArrays[0][i].getFConst();
2686 float x = unionArrays[1][i].getFConst();
2687 // Results are undefined if x and y are both 0.
2688 if (x == 0.0f && y == 0.0f)
2689 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2690 else
2691 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302692 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002693 break;
2694 }
Arun Patolebf790422015-05-18 17:53:04 +05302695
Olli Etuaho51182ab2017-01-22 00:12:29 +00002696 case EOpPow:
2697 {
2698 ASSERT(basicType == EbtFloat);
2699 resultArray = new TConstantUnion[maxObjectSize];
2700 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302701 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002702 float x = unionArrays[0][i].getFConst();
2703 float y = unionArrays[1][i].getFConst();
2704 // Results are undefined if x < 0.
2705 // Results are undefined if x = 0 and y <= 0.
2706 if (x < 0.0f)
2707 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2708 else if (x == 0.0f && y <= 0.0f)
2709 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2710 else
2711 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302712 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002713 break;
2714 }
Arun Patolebf790422015-05-18 17:53:04 +05302715
Olli Etuaho51182ab2017-01-22 00:12:29 +00002716 case EOpMod:
2717 {
2718 ASSERT(basicType == EbtFloat);
2719 resultArray = new TConstantUnion[maxObjectSize];
2720 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302721 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002722 float x = unionArrays[0][i].getFConst();
2723 float y = unionArrays[1][i].getFConst();
2724 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302725 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002726 break;
2727 }
Arun Patolebf790422015-05-18 17:53:04 +05302728
Olli Etuaho51182ab2017-01-22 00:12:29 +00002729 case EOpMin:
2730 {
2731 resultArray = new TConstantUnion[maxObjectSize];
2732 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302733 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002734 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302735 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002736 case EbtFloat:
2737 resultArray[i].setFConst(
2738 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2739 break;
2740 case EbtInt:
2741 resultArray[i].setIConst(
2742 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2743 break;
2744 case EbtUInt:
2745 resultArray[i].setUConst(
2746 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2747 break;
2748 default:
2749 UNREACHABLE();
2750 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302751 }
2752 }
2753 break;
Arun Patole274f0702015-05-05 13:33:30 +05302754 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002755
2756 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302757 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002758 resultArray = new TConstantUnion[maxObjectSize];
2759 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302760 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002761 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302762 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002763 case EbtFloat:
2764 resultArray[i].setFConst(
2765 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2766 break;
2767 case EbtInt:
2768 resultArray[i].setIConst(
2769 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2770 break;
2771 case EbtUInt:
2772 resultArray[i].setUConst(
2773 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2774 break;
2775 default:
2776 UNREACHABLE();
2777 break;
Arun Patole274f0702015-05-05 13:33:30 +05302778 }
2779 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002780 break;
Arun Patole274f0702015-05-05 13:33:30 +05302781 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002782
2783 case EOpStep:
2784 {
2785 ASSERT(basicType == EbtFloat);
2786 resultArray = new TConstantUnion[maxObjectSize];
2787 for (size_t i = 0; i < maxObjectSize; i++)
2788 resultArray[i].setFConst(
2789 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2790 break;
2791 }
2792
2793 case EOpLessThanComponentWise:
2794 {
2795 resultArray = new TConstantUnion[maxObjectSize];
2796 for (size_t i = 0; i < maxObjectSize; i++)
2797 {
2798 switch (basicType)
2799 {
2800 case EbtFloat:
2801 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2802 unionArrays[1][i].getFConst());
2803 break;
2804 case EbtInt:
2805 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2806 unionArrays[1][i].getIConst());
2807 break;
2808 case EbtUInt:
2809 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2810 unionArrays[1][i].getUConst());
2811 break;
2812 default:
2813 UNREACHABLE();
2814 break;
2815 }
2816 }
2817 break;
2818 }
2819
2820 case EOpLessThanEqualComponentWise:
2821 {
2822 resultArray = new TConstantUnion[maxObjectSize];
2823 for (size_t i = 0; i < maxObjectSize; i++)
2824 {
2825 switch (basicType)
2826 {
2827 case EbtFloat:
2828 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2829 unionArrays[1][i].getFConst());
2830 break;
2831 case EbtInt:
2832 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2833 unionArrays[1][i].getIConst());
2834 break;
2835 case EbtUInt:
2836 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2837 unionArrays[1][i].getUConst());
2838 break;
2839 default:
2840 UNREACHABLE();
2841 break;
2842 }
2843 }
2844 break;
2845 }
2846
2847 case EOpGreaterThanComponentWise:
2848 {
2849 resultArray = new TConstantUnion[maxObjectSize];
2850 for (size_t i = 0; i < maxObjectSize; i++)
2851 {
2852 switch (basicType)
2853 {
2854 case EbtFloat:
2855 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2856 unionArrays[1][i].getFConst());
2857 break;
2858 case EbtInt:
2859 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2860 unionArrays[1][i].getIConst());
2861 break;
2862 case EbtUInt:
2863 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2864 unionArrays[1][i].getUConst());
2865 break;
2866 default:
2867 UNREACHABLE();
2868 break;
2869 }
2870 }
2871 break;
2872 }
2873 case EOpGreaterThanEqualComponentWise:
2874 {
2875 resultArray = new TConstantUnion[maxObjectSize];
2876 for (size_t i = 0; i < maxObjectSize; i++)
2877 {
2878 switch (basicType)
2879 {
2880 case EbtFloat:
2881 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2882 unionArrays[1][i].getFConst());
2883 break;
2884 case EbtInt:
2885 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2886 unionArrays[1][i].getIConst());
2887 break;
2888 case EbtUInt:
2889 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2890 unionArrays[1][i].getUConst());
2891 break;
2892 default:
2893 UNREACHABLE();
2894 break;
2895 }
2896 }
2897 }
2898 break;
2899
2900 case EOpEqualComponentWise:
2901 {
2902 resultArray = new TConstantUnion[maxObjectSize];
2903 for (size_t i = 0; i < maxObjectSize; i++)
2904 {
2905 switch (basicType)
2906 {
2907 case EbtFloat:
2908 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2909 unionArrays[1][i].getFConst());
2910 break;
2911 case EbtInt:
2912 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2913 unionArrays[1][i].getIConst());
2914 break;
2915 case EbtUInt:
2916 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2917 unionArrays[1][i].getUConst());
2918 break;
2919 case EbtBool:
2920 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2921 unionArrays[1][i].getBConst());
2922 break;
2923 default:
2924 UNREACHABLE();
2925 break;
2926 }
2927 }
2928 break;
2929 }
2930
2931 case EOpNotEqualComponentWise:
2932 {
2933 resultArray = new TConstantUnion[maxObjectSize];
2934 for (size_t i = 0; i < maxObjectSize; i++)
2935 {
2936 switch (basicType)
2937 {
2938 case EbtFloat:
2939 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2940 unionArrays[1][i].getFConst());
2941 break;
2942 case EbtInt:
2943 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2944 unionArrays[1][i].getIConst());
2945 break;
2946 case EbtUInt:
2947 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2948 unionArrays[1][i].getUConst());
2949 break;
2950 case EbtBool:
2951 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2952 unionArrays[1][i].getBConst());
2953 break;
2954 default:
2955 UNREACHABLE();
2956 break;
2957 }
2958 }
2959 break;
2960 }
2961
2962 case EOpDistance:
2963 {
2964 ASSERT(basicType == EbtFloat);
2965 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2966 resultArray = new TConstantUnion();
2967 for (size_t i = 0; i < maxObjectSize; i++)
2968 {
2969 float x = unionArrays[0][i].getFConst();
2970 float y = unionArrays[1][i].getFConst();
2971 distanceArray[i].setFConst(x - y);
2972 }
2973 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2974 break;
2975 }
2976
2977 case EOpDot:
2978 ASSERT(basicType == EbtFloat);
2979 resultArray = new TConstantUnion();
2980 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2981 break;
2982
2983 case EOpCross:
2984 {
2985 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2986 resultArray = new TConstantUnion[maxObjectSize];
2987 float x0 = unionArrays[0][0].getFConst();
2988 float x1 = unionArrays[0][1].getFConst();
2989 float x2 = unionArrays[0][2].getFConst();
2990 float y0 = unionArrays[1][0].getFConst();
2991 float y1 = unionArrays[1][1].getFConst();
2992 float y2 = unionArrays[1][2].getFConst();
2993 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2994 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2995 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2996 break;
2997 }
2998
2999 case EOpReflect:
3000 {
3001 ASSERT(basicType == EbtFloat);
3002 // genType reflect (genType I, genType N) :
3003 // For the incident vector I and surface orientation N, returns the reflection
3004 // direction:
3005 // I - 2 * dot(N, I) * N.
3006 resultArray = new TConstantUnion[maxObjectSize];
3007 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3008 for (size_t i = 0; i < maxObjectSize; i++)
3009 {
3010 float result = unionArrays[0][i].getFConst() -
3011 2.0f * dotProduct * unionArrays[1][i].getFConst();
3012 resultArray[i].setFConst(result);
3013 }
3014 break;
3015 }
3016
3017 case EOpMulMatrixComponentWise:
3018 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003019 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3020 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003021 // Perform component-wise matrix multiplication.
3022 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003023 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003024 angle::Matrix<float> result =
3025 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3026 SetUnionArrayFromMatrix(result, resultArray);
3027 break;
3028 }
3029
3030 case EOpOuterProduct:
3031 {
3032 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003033 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3034 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003035 resultArray = new TConstantUnion[numRows * numCols];
3036 angle::Matrix<float> result =
3037 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3038 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3039 SetUnionArrayFromMatrix(result, resultArray);
3040 break;
3041 }
3042
3043 case EOpClamp:
3044 {
3045 resultArray = new TConstantUnion[maxObjectSize];
3046 for (size_t i = 0; i < maxObjectSize; i++)
3047 {
3048 switch (basicType)
3049 {
3050 case EbtFloat:
3051 {
3052 float x = unionArrays[0][i].getFConst();
3053 float min = unionArrays[1][i].getFConst();
3054 float max = unionArrays[2][i].getFConst();
3055 // Results are undefined if min > max.
3056 if (min > max)
3057 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3058 &resultArray[i]);
3059 else
3060 resultArray[i].setFConst(gl::clamp(x, min, max));
3061 break;
3062 }
3063
3064 case EbtInt:
3065 {
3066 int x = unionArrays[0][i].getIConst();
3067 int min = unionArrays[1][i].getIConst();
3068 int max = unionArrays[2][i].getIConst();
3069 // Results are undefined if min > max.
3070 if (min > max)
3071 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3072 &resultArray[i]);
3073 else
3074 resultArray[i].setIConst(gl::clamp(x, min, max));
3075 break;
3076 }
3077 case EbtUInt:
3078 {
3079 unsigned int x = unionArrays[0][i].getUConst();
3080 unsigned int min = unionArrays[1][i].getUConst();
3081 unsigned int max = unionArrays[2][i].getUConst();
3082 // Results are undefined if min > max.
3083 if (min > max)
3084 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3085 &resultArray[i]);
3086 else
3087 resultArray[i].setUConst(gl::clamp(x, min, max));
3088 break;
3089 }
3090 default:
3091 UNREACHABLE();
3092 break;
3093 }
3094 }
3095 break;
3096 }
3097
3098 case EOpMix:
3099 {
3100 ASSERT(basicType == EbtFloat);
3101 resultArray = new TConstantUnion[maxObjectSize];
3102 for (size_t i = 0; i < maxObjectSize; i++)
3103 {
3104 float x = unionArrays[0][i].getFConst();
3105 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003106 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003107 if (type == EbtFloat)
3108 {
3109 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3110 float a = unionArrays[2][i].getFConst();
3111 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3112 }
3113 else // 3rd parameter is EbtBool
3114 {
3115 ASSERT(type == EbtBool);
3116 // Selects which vector each returned component comes from.
3117 // For a component of a that is false, the corresponding component of x is
3118 // returned.
3119 // For a component of a that is true, the corresponding component of y is
3120 // returned.
3121 bool a = unionArrays[2][i].getBConst();
3122 resultArray[i].setFConst(a ? y : x);
3123 }
3124 }
3125 break;
3126 }
3127
3128 case EOpSmoothStep:
3129 {
3130 ASSERT(basicType == EbtFloat);
3131 resultArray = new TConstantUnion[maxObjectSize];
3132 for (size_t i = 0; i < maxObjectSize; i++)
3133 {
3134 float edge0 = unionArrays[0][i].getFConst();
3135 float edge1 = unionArrays[1][i].getFConst();
3136 float x = unionArrays[2][i].getFConst();
3137 // Results are undefined if edge0 >= edge1.
3138 if (edge0 >= edge1)
3139 {
3140 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3141 }
3142 else
3143 {
3144 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3145 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3146 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3147 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3148 }
3149 }
3150 break;
3151 }
3152
Olli Etuaho74da73f2017-02-01 15:37:48 +00003153 case EOpLdexp:
3154 {
3155 resultArray = new TConstantUnion[maxObjectSize];
3156 for (size_t i = 0; i < maxObjectSize; i++)
3157 {
3158 float x = unionArrays[0][i].getFConst();
3159 int exp = unionArrays[1][i].getIConst();
3160 if (exp > 128)
3161 {
3162 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3163 }
3164 else
3165 {
3166 resultArray[i].setFConst(gl::Ldexp(x, exp));
3167 }
3168 }
3169 break;
3170 }
3171
Olli Etuaho51182ab2017-01-22 00:12:29 +00003172 case EOpFaceForward:
3173 {
3174 ASSERT(basicType == EbtFloat);
3175 // genType faceforward(genType N, genType I, genType Nref) :
3176 // If dot(Nref, I) < 0 return N, otherwise return -N.
3177 resultArray = new TConstantUnion[maxObjectSize];
3178 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3179 for (size_t i = 0; i < maxObjectSize; i++)
3180 {
3181 if (dotProduct < 0)
3182 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3183 else
3184 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3185 }
3186 break;
3187 }
3188
3189 case EOpRefract:
3190 {
3191 ASSERT(basicType == EbtFloat);
3192 // genType refract(genType I, genType N, float eta) :
3193 // For the incident vector I and surface normal N, and the ratio of indices of
3194 // refraction eta,
3195 // return the refraction vector. The result is computed by
3196 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3197 // if (k < 0.0)
3198 // return genType(0.0)
3199 // else
3200 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3201 resultArray = new TConstantUnion[maxObjectSize];
3202 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3203 for (size_t i = 0; i < maxObjectSize; i++)
3204 {
3205 float eta = unionArrays[2][i].getFConst();
3206 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3207 if (k < 0.0f)
3208 resultArray[i].setFConst(0.0f);
3209 else
3210 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3211 (eta * dotProduct + sqrtf(k)) *
3212 unionArrays[1][i].getFConst());
3213 }
3214 break;
3215 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003216 case EOpBitfieldExtract:
3217 {
3218 resultArray = new TConstantUnion[maxObjectSize];
3219 for (size_t i = 0; i < maxObjectSize; ++i)
3220 {
3221 int offset = unionArrays[1][0].getIConst();
3222 int bits = unionArrays[2][0].getIConst();
3223 if (bits == 0)
3224 {
3225 if (aggregate->getBasicType() == EbtInt)
3226 {
3227 resultArray[i].setIConst(0);
3228 }
3229 else
3230 {
3231 ASSERT(aggregate->getBasicType() == EbtUInt);
3232 resultArray[i].setUConst(0);
3233 }
3234 }
3235 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3236 {
3237 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3238 &resultArray[i]);
3239 }
3240 else
3241 {
3242 // bits can be 32 here, so we need to avoid bit shift overflow.
3243 uint32_t maskMsb = 1u << (bits - 1);
3244 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3245 if (aggregate->getBasicType() == EbtInt)
3246 {
3247 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3248 uint32_t resultUnsigned = (value & mask) >> offset;
3249 if ((resultUnsigned & maskMsb) != 0)
3250 {
3251 // The most significant bits (from bits+1 to the most significant bit)
3252 // should be set to 1.
3253 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3254 resultUnsigned |= higherBitsMask;
3255 }
3256 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3257 }
3258 else
3259 {
3260 ASSERT(aggregate->getBasicType() == EbtUInt);
3261 uint32_t value = unionArrays[0][i].getUConst();
3262 resultArray[i].setUConst((value & mask) >> offset);
3263 }
3264 }
3265 }
3266 break;
3267 }
3268 case EOpBitfieldInsert:
3269 {
3270 resultArray = new TConstantUnion[maxObjectSize];
3271 for (size_t i = 0; i < maxObjectSize; ++i)
3272 {
3273 int offset = unionArrays[2][0].getIConst();
3274 int bits = unionArrays[3][0].getIConst();
3275 if (bits == 0)
3276 {
3277 if (aggregate->getBasicType() == EbtInt)
3278 {
3279 int32_t base = unionArrays[0][i].getIConst();
3280 resultArray[i].setIConst(base);
3281 }
3282 else
3283 {
3284 ASSERT(aggregate->getBasicType() == EbtUInt);
3285 uint32_t base = unionArrays[0][i].getUConst();
3286 resultArray[i].setUConst(base);
3287 }
3288 }
3289 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3290 {
3291 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3292 &resultArray[i]);
3293 }
3294 else
3295 {
3296 // bits can be 32 here, so we need to avoid bit shift overflow.
3297 uint32_t maskMsb = 1u << (bits - 1);
3298 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3299 uint32_t baseMask = ~insertMask;
3300 if (aggregate->getBasicType() == EbtInt)
3301 {
3302 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3303 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3304 uint32_t resultUnsigned =
3305 (base & baseMask) | ((insert << offset) & insertMask);
3306 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3307 }
3308 else
3309 {
3310 ASSERT(aggregate->getBasicType() == EbtUInt);
3311 uint32_t base = unionArrays[0][i].getUConst();
3312 uint32_t insert = unionArrays[1][i].getUConst();
3313 resultArray[i].setUConst((base & baseMask) |
3314 ((insert << offset) & insertMask));
3315 }
3316 }
3317 }
3318 break;
3319 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003320
3321 default:
3322 UNREACHABLE();
3323 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303324 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003325 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303326}
3327
3328// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04003329TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
3330{
Yunchao He4f285442017-04-21 12:15:49 +08003331 if (hashFunction == nullptr || name.empty())
Jamie Madillb1a85f42014-08-19 15:23:24 -04003332 return name;
3333 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
3334 TStringStream stream;
3335 stream << HASHED_NAME_PREFIX << std::hex << number;
3336 TString hashedName = stream.str();
3337 return hashedName;
3338}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003339
3340void TIntermTraverser::updateTree()
3341{
Olli Etuahoa6f22092015-05-08 18:31:10 +03003342 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
3343 {
3344 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
3345 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003346 if (!insertion.insertionsAfter.empty())
3347 {
3348 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
3349 insertion.insertionsAfter);
3350 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003351 }
3352 if (!insertion.insertionsBefore.empty())
3353 {
3354 bool inserted =
3355 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
3356 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003357 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03003358 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003359 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
3360 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003361 const NodeUpdateEntry &replacement = mReplacements[ii];
3362 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003363 bool replaced =
3364 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003365 ASSERT(replaced);
3366
Olli Etuahocd94ef92015-04-16 19:18:10 +03003367 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003368 {
3369 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03003370 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003371 // be replaced, we need to make sure we don't update the replaced
3372 // node; instead, we update the replacement node.
3373 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
3374 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003375 NodeUpdateEntry &replacement2 = mReplacements[jj];
3376 if (replacement2.parent == replacement.original)
3377 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003378 }
3379 }
3380 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003381 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
3382 {
3383 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
3384 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003385 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
3386 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003387 ASSERT(replaced);
3388 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03003389
Jamie Madill03d863c2016-07-27 18:15:53 -04003390 clearReplacementQueue();
3391}
3392
3393void TIntermTraverser::clearReplacementQueue()
3394{
Olli Etuahod4f303e2015-05-20 17:09:06 +03003395 mReplacements.clear();
3396 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04003397 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003398}
Jamie Madill1048e432016-07-23 18:51:28 -04003399
Jamie Madill03d863c2016-07-27 18:15:53 -04003400void TIntermTraverser::queueReplacement(TIntermNode *original,
3401 TIntermNode *replacement,
3402 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003403{
Jamie Madill03d863c2016-07-27 18:15:53 -04003404 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04003405}
3406
Jamie Madill03d863c2016-07-27 18:15:53 -04003407void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
3408 TIntermNode *original,
3409 TIntermNode *replacement,
3410 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003411{
Jamie Madill03d863c2016-07-27 18:15:53 -04003412 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
3413 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04003414}
Jamie Madill45bcc782016-11-07 13:58:48 -05003415
Olli Etuahofe486322017-03-21 09:30:54 +00003416TName TIntermTraverser::GetInternalFunctionName(const char *name)
3417{
3418 TString nameStr(name);
Olli Etuahofe486322017-03-21 09:30:54 +00003419 TName nameObj(nameStr);
3420 nameObj.setInternal(true);
3421 return nameObj;
3422}
3423
3424TIntermFunctionPrototype *TIntermTraverser::CreateInternalFunctionPrototypeNode(
3425 const TType &returnType,
3426 const char *name,
3427 const TSymbolUniqueId &functionId)
3428{
3429 TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType, functionId);
3430 functionNode->getFunctionSymbolInfo()->setNameObj(GetInternalFunctionName(name));
3431 return functionNode;
3432}
3433
3434TIntermFunctionDefinition *TIntermTraverser::CreateInternalFunctionDefinitionNode(
3435 const TType &returnType,
3436 const char *name,
3437 TIntermBlock *functionBody,
3438 const TSymbolUniqueId &functionId)
3439{
3440 TIntermFunctionPrototype *prototypeNode =
3441 CreateInternalFunctionPrototypeNode(returnType, name, functionId);
3442 return new TIntermFunctionDefinition(prototypeNode, functionBody);
3443}
3444
3445TIntermAggregate *TIntermTraverser::CreateInternalFunctionCallNode(
3446 const TType &returnType,
3447 const char *name,
3448 const TSymbolUniqueId &functionId,
3449 TIntermSequence *arguments)
3450{
3451 TIntermAggregate *functionNode = TIntermAggregate::CreateFunctionCall(
3452 returnType, functionId, GetInternalFunctionName(name), arguments);
3453 return functionNode;
3454}
3455
Jamie Madill45bcc782016-11-07 13:58:48 -05003456} // namespace sh