blob: 0e3722cdaf76f7f13a825cbb74a5fd1dac496122 [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 Etuaho8fab3202017-05-08 18:22:22 +0300309 return new TIntermAggregate(type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000310}
311
312TIntermAggregate *TIntermAggregate::Create(const TType &type,
313 TOperator op,
314 TIntermSequence *arguments)
315{
316 TIntermAggregate *node = new TIntermAggregate(type, op, arguments);
317 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
318 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
319 ASSERT(!node->isConstructor()); // Should use CreateConstructor
320 return node;
321}
322
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800323TIntermAggregate::TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments)
324 : TIntermOperator(op), mUseEmulatedFunction(false), mGotPrecisionFromChildren(false)
325{
326 if (arguments != nullptr)
327 {
328 mArguments.swap(*arguments);
329 }
330 setTypePrecisionAndQualifier(type);
331}
332
333void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
334{
335 setType(type);
336 mType.setQualifier(EvqTemporary);
337 if (!isFunctionCall())
338 {
339 if (isConstructor())
340 {
341 // Structs should not be precision qualified, the individual members may be.
342 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300343 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800344 {
345 setPrecisionFromChildren();
346 }
347 }
348 else
349 {
350 setPrecisionForBuiltInOp();
351 }
352 if (areChildrenConstQualified())
353 {
354 mType.setQualifier(EvqConst);
355 }
356 }
357}
358
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200359bool TIntermAggregate::areChildrenConstQualified()
360{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800361 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200362 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800363 TIntermTyped *typedArg = arg->getAsTyped();
364 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200365 {
366 return false;
367 }
368 }
369 return true;
370}
371
Olli Etuahod2a67b92014-10-21 16:42:57 +0300372void TIntermAggregate::setPrecisionFromChildren()
373{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300374 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300375 if (getBasicType() == EbtBool)
376 {
377 mType.setPrecision(EbpUndefined);
378 return;
379 }
380
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500381 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800382 TIntermSequence::iterator childIter = mArguments.begin();
383 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300384 {
385 TIntermTyped *typed = (*childIter)->getAsTyped();
386 if (typed)
387 precision = GetHigherPrecision(typed->getPrecision(), precision);
388 ++childIter;
389 }
390 mType.setPrecision(precision);
391}
392
Olli Etuaho9250cb22017-01-21 10:51:27 +0000393void TIntermAggregate::setPrecisionForBuiltInOp()
394{
395 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800396 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000397 if (!setPrecisionForSpecialBuiltInOp())
398 {
399 setPrecisionFromChildren();
400 }
401}
402
403bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
404{
405 switch (mOp)
406 {
407 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800408 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
409 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000410 return true;
411 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800412 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
413 mArguments[1]->getAsTyped()->getPrecision()));
414 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000415 return true;
416 case EOpUaddCarry:
417 case EOpUsubBorrow:
418 mType.setPrecision(EbpHigh);
419 return true;
420 default:
421 return false;
422 }
423}
424
Olli Etuahod2a67b92014-10-21 16:42:57 +0300425void TIntermAggregate::setBuiltInFunctionPrecision()
426{
427 // All built-ins returning bool should be handled as ops, not functions.
428 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800429 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300430
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800431 TPrecision precision = EbpUndefined;
432 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300433 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800434 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300435 // ESSL spec section 8: texture functions get their precision from the sampler.
436 if (typed && IsSampler(typed->getBasicType()))
437 {
438 precision = typed->getPrecision();
439 break;
440 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300441 }
442 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
443 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100444 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300445 mType.setPrecision(EbpHigh);
446 else
447 mType.setPrecision(precision);
448}
449
Olli Etuahof2209f72017-04-01 12:45:55 +0300450TString TIntermAggregate::getSymbolTableMangledName() const
451{
452 ASSERT(!isConstructor());
453 switch (mOp)
454 {
455 case EOpCallInternalRawFunction:
456 case EOpCallBuiltInFunction:
457 case EOpCallFunctionInAST:
458 return TFunction::GetMangledNameFromCall(mFunctionInfo.getName(), mArguments);
459 default:
460 TString opString = GetOperatorString(mOp);
461 return TFunction::GetMangledNameFromCall(opString, mArguments);
462 }
463}
464
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300465bool TIntermAggregate::hasSideEffects() const
466{
467 if (isFunctionCall() && mFunctionInfo.isKnownToNotHaveSideEffects())
468 {
469 for (TIntermNode *arg : mArguments)
470 {
471 if (arg->getAsTyped()->hasSideEffects())
472 {
473 return true;
474 }
475 }
476 return false;
477 }
478 // Conservatively assume most aggregate operators have side-effects
479 return true;
480}
481
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100482void TIntermBlock::appendStatement(TIntermNode *statement)
483{
Olli Etuaho13389b62016-10-16 11:48:18 +0100484 // Declaration nodes with no children can appear if all the declarators just added constants to
485 // the symbol table instead of generating code. They're no-ops so they aren't added to blocks.
486 if (statement != nullptr && (statement->getAsDeclarationNode() == nullptr ||
487 !statement->getAsDeclarationNode()->getSequence()->empty()))
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100488 {
489 mStatements.push_back(statement);
490 }
491}
492
Olli Etuaho16c745a2017-01-16 17:02:27 +0000493void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
494{
495 ASSERT(parameter != nullptr);
496 mParameters.push_back(parameter);
497}
498
Olli Etuaho13389b62016-10-16 11:48:18 +0100499void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
500{
501 ASSERT(declarator != nullptr);
502 ASSERT(declarator->getAsSymbolNode() != nullptr ||
503 (declarator->getAsBinaryNode() != nullptr &&
504 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
505 ASSERT(mDeclarators.empty() ||
506 declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType()));
507 mDeclarators.push_back(declarator);
508}
509
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300510bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
511{
512 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
513 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
514 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
515 return false;
516}
517
Olli Etuaho57961272016-09-14 13:57:46 +0300518bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400519{
520 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100521 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
522 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400523 return false;
524}
525
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500526bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200527{
528 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100529 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200530 return false;
531}
532
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500533bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200534{
535 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
536 return false;
537}
538
Olli Etuahod7a25242015-08-18 13:49:45 +0300539TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
540{
541 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
542 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
543 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
544 mLine = node.mLine;
545}
546
Olli Etuahod4f4c112016-04-15 15:11:24 +0300547bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
548{
549 TIntermAggregate *constructor = getAsAggregate();
550 if (!constructor || !constructor->isConstructor())
551 {
552 return false;
553 }
554 for (TIntermNode *&node : *constructor->getSequence())
555 {
556 if (!node->getAsConstantUnion())
557 return false;
558 }
559 return true;
560}
561
Corentin Wallez509e4562016-08-25 14:55:44 -0400562// static
563TIntermTyped *TIntermTyped::CreateIndexNode(int index)
564{
565 TConstantUnion *u = new TConstantUnion[1];
566 u[0].setIConst(index);
567
568 TType type(EbtInt, EbpUndefined, EvqConst, 1);
569 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
570 return node;
571}
572
573// static
574TIntermTyped *TIntermTyped::CreateZero(const TType &type)
575{
576 TType constType(type);
577 constType.setQualifier(EvqConst);
578
579 if (!type.isArray() && type.getBasicType() != EbtStruct)
580 {
Corentin Wallez509e4562016-08-25 14:55:44 -0400581 size_t size = constType.getObjectSize();
582 TConstantUnion *u = new TConstantUnion[size];
583 for (size_t i = 0; i < size; ++i)
584 {
585 switch (type.getBasicType())
586 {
587 case EbtFloat:
588 u[i].setFConst(0.0f);
589 break;
590 case EbtInt:
591 u[i].setIConst(0);
592 break;
593 case EbtUInt:
594 u[i].setUConst(0u);
595 break;
596 case EbtBool:
597 u[i].setBConst(false);
598 break;
599 default:
Corentin Wallez17a5c062017-01-22 15:20:53 -0500600 // CreateZero is called by ParseContext that keeps parsing even when an error
601 // occurs, so it is possible for CreateZero to be called with non-basic types.
602 // This happens only on error condition but CreateZero needs to return a value
603 // with the correct type to continue the typecheck. That's why we handle
604 // non-basic type by setting whatever value, we just need the type to be right.
605 u[i].setIConst(42);
606 break;
Corentin Wallez509e4562016-08-25 14:55:44 -0400607 }
608 }
609
610 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
611 return node;
612 }
613
Olli Etuaho193c0952017-05-02 15:51:47 +0300614 if (type.getBasicType() == EbtVoid)
615 {
616 // Void array. This happens only on error condition, similarly to the case above. We don't
617 // have a constructor operator for void, so this needs special handling. We'll end up with a
618 // value without the array type, but that should not be a problem.
619 constType.clearArrayness();
620 return CreateZero(constType);
621 }
622
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800623 TIntermSequence *arguments = new TIntermSequence();
Corentin Wallez509e4562016-08-25 14:55:44 -0400624
625 if (type.isArray())
626 {
627 TType elementType(type);
628 elementType.clearArrayness();
629
630 size_t arraySize = type.getArraySize();
631 for (size_t i = 0; i < arraySize; ++i)
632 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800633 arguments->push_back(CreateZero(elementType));
Corentin Wallez509e4562016-08-25 14:55:44 -0400634 }
635 }
636 else
637 {
638 ASSERT(type.getBasicType() == EbtStruct);
639
640 TStructure *structure = type.getStruct();
641 for (const auto &field : structure->fields())
642 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800643 arguments->push_back(CreateZero(*field->type()));
Corentin Wallez509e4562016-08-25 14:55:44 -0400644 }
645 }
646
Olli Etuahoa7ecec32017-05-08 17:43:55 +0300647 return TIntermAggregate::CreateConstructor(constType, arguments);
Corentin Wallez509e4562016-08-25 14:55:44 -0400648}
649
Corentin Wallez36fd1002016-12-08 11:30:44 -0500650// static
651TIntermTyped *TIntermTyped::CreateBool(bool value)
652{
653 TConstantUnion *u = new TConstantUnion[1];
654 u[0].setBConst(value);
655
656 TType type(EbtBool, EbpUndefined, EvqConst, 1);
657 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
658 return node;
659}
660
Olli Etuahod7a25242015-08-18 13:49:45 +0300661TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
662{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200663 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300664}
665
Olli Etuahobd674552016-10-06 13:28:42 +0100666void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
667{
Olli Etuahoec9232b2017-03-27 17:01:37 +0300668 setName(function.getName());
Olli Etuahofe486322017-03-21 09:30:54 +0000669 setId(TSymbolUniqueId(function));
670}
671
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300672TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id)
673 : mId(new TSymbolUniqueId(id)), mKnownToNotHaveSideEffects(false)
Olli Etuahofe486322017-03-21 09:30:54 +0000674{
675}
676
677TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300678 : mName(info.mName), mId(nullptr), mKnownToNotHaveSideEffects(info.mKnownToNotHaveSideEffects)
Olli Etuahofe486322017-03-21 09:30:54 +0000679{
680 if (info.mId)
681 {
682 mId = new TSymbolUniqueId(*info.mId);
683 }
684}
685
686TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
687{
688 mName = info.mName;
689 if (info.mId)
690 {
691 mId = new TSymbolUniqueId(*info.mId);
692 }
693 else
694 {
695 mId = nullptr;
696 }
697 return *this;
698}
699
700void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
701{
702 mId = new TSymbolUniqueId(id);
703}
704
705const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
706{
707 ASSERT(mId);
708 return *mId;
Olli Etuahobd674552016-10-06 13:28:42 +0100709}
710
Olli Etuahod7a25242015-08-18 13:49:45 +0300711TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
712 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300713 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100714 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
715 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300716{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800717 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300718 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800719 TIntermTyped *typedArg = arg->getAsTyped();
720 ASSERT(typedArg != nullptr);
721 TIntermTyped *argCopy = typedArg->deepCopy();
722 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300723 }
724}
725
Olli Etuahofe486322017-03-21 09:30:54 +0000726TIntermAggregate *TIntermAggregate::shallowCopy() const
727{
728 TIntermSequence *copySeq = new TIntermSequence();
729 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
730 TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq);
731 *copyNode->getFunctionSymbolInfo() = mFunctionInfo;
732 copyNode->setLine(mLine);
733 return copyNode;
734}
735
Olli Etuahob6fa0432016-09-28 16:28:05 +0100736TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
737{
738 TIntermTyped *operandCopy = node.mOperand->deepCopy();
739 ASSERT(operandCopy != nullptr);
740 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000741 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100742}
743
Olli Etuahod7a25242015-08-18 13:49:45 +0300744TIntermBinary::TIntermBinary(const TIntermBinary &node)
745 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
746{
747 TIntermTyped *leftCopy = node.mLeft->deepCopy();
748 TIntermTyped *rightCopy = node.mRight->deepCopy();
749 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
750 mLeft = leftCopy;
751 mRight = rightCopy;
752}
753
754TIntermUnary::TIntermUnary(const TIntermUnary &node)
755 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
756{
757 TIntermTyped *operandCopy = node.mOperand->deepCopy();
758 ASSERT(operandCopy != nullptr);
759 mOperand = operandCopy;
760}
761
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300762TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300763{
Olli Etuahod7a25242015-08-18 13:49:45 +0300764 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300765 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
766 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300767 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300768 mCondition = conditionCopy;
769 mTrueExpression = trueCopy;
770 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300771}
772
Jamie Madillb1a85f42014-08-19 15:23:24 -0400773bool TIntermOperator::isAssignment() const
774{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300775 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400776}
777
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300778bool TIntermOperator::isMultiplication() const
779{
780 switch (mOp)
781 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500782 case EOpMul:
783 case EOpMatrixTimesMatrix:
784 case EOpMatrixTimesVector:
785 case EOpMatrixTimesScalar:
786 case EOpVectorTimesMatrix:
787 case EOpVectorTimesScalar:
788 return true;
789 default:
790 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300791 }
792}
793
Jamie Madillb1a85f42014-08-19 15:23:24 -0400794bool TIntermOperator::isConstructor() const
795{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300796 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400797}
798
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800799bool TIntermOperator::isFunctionCall() const
800{
801 switch (mOp)
802 {
803 case EOpCallFunctionInAST:
804 case EOpCallBuiltInFunction:
805 case EOpCallInternalRawFunction:
806 return true;
807 default:
808 return false;
809 }
810}
811
Olli Etuaho1dded802016-08-18 18:13:13 +0300812TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
813{
814 if (left.isMatrix())
815 {
816 if (right.isMatrix())
817 {
818 return EOpMatrixTimesMatrix;
819 }
820 else
821 {
822 if (right.isVector())
823 {
824 return EOpMatrixTimesVector;
825 }
826 else
827 {
828 return EOpMatrixTimesScalar;
829 }
830 }
831 }
832 else
833 {
834 if (right.isMatrix())
835 {
836 if (left.isVector())
837 {
838 return EOpVectorTimesMatrix;
839 }
840 else
841 {
842 return EOpMatrixTimesScalar;
843 }
844 }
845 else
846 {
847 // Neither operand is a matrix.
848 if (left.isVector() == right.isVector())
849 {
850 // Leave as component product.
851 return EOpMul;
852 }
853 else
854 {
855 return EOpVectorTimesScalar;
856 }
857 }
858 }
859}
860
861TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
862{
863 if (left.isMatrix())
864 {
865 if (right.isMatrix())
866 {
867 return EOpMatrixTimesMatrixAssign;
868 }
869 else
870 {
871 // right should be scalar, but this may not be validated yet.
872 return EOpMatrixTimesScalarAssign;
873 }
874 }
875 else
876 {
877 if (right.isMatrix())
878 {
879 // Left should be a vector, but this may not be validated yet.
880 return EOpVectorTimesMatrixAssign;
881 }
882 else
883 {
884 // Neither operand is a matrix.
885 if (left.isVector() == right.isVector())
886 {
887 // Leave as component product.
888 return EOpMulAssign;
889 }
890 else
891 {
892 // left should be vector and right should be scalar, but this may not be validated
893 // yet.
894 return EOpVectorTimesScalarAssign;
895 }
896 }
897 }
898}
899
Jamie Madillb1a85f42014-08-19 15:23:24 -0400900//
901// Make sure the type of a unary operator is appropriate for its
902// combination of operation and operand type.
903//
Olli Etuahoa2234302016-08-31 12:05:39 +0300904void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400905{
Olli Etuahoa2234302016-08-31 12:05:39 +0300906 TQualifier resultQualifier = EvqTemporary;
907 if (mOperand->getQualifier() == EvqConst)
908 resultQualifier = EvqConst;
909
910 unsigned char operandPrimarySize =
911 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400912 switch (mOp)
913 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300914 case EOpFloatBitsToInt:
915 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
916 break;
917 case EOpFloatBitsToUint:
918 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
919 break;
920 case EOpIntBitsToFloat:
921 case EOpUintBitsToFloat:
922 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
923 break;
924 case EOpPackSnorm2x16:
925 case EOpPackUnorm2x16:
926 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800927 case EOpPackUnorm4x8:
928 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300929 setType(TType(EbtUInt, EbpHigh, resultQualifier));
930 break;
931 case EOpUnpackSnorm2x16:
932 case EOpUnpackUnorm2x16:
933 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
934 break;
935 case EOpUnpackHalf2x16:
936 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
937 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800938 case EOpUnpackUnorm4x8:
939 case EOpUnpackSnorm4x8:
940 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
941 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300942 case EOpAny:
943 case EOpAll:
944 setType(TType(EbtBool, EbpUndefined, resultQualifier));
945 break;
946 case EOpLength:
947 case EOpDeterminant:
948 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
949 break;
950 case EOpTranspose:
951 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
952 static_cast<unsigned char>(mOperand->getType().getRows()),
953 static_cast<unsigned char>(mOperand->getType().getCols())));
954 break;
955 case EOpIsInf:
956 case EOpIsNan:
957 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
958 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000959 case EOpBitfieldReverse:
960 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
961 break;
962 case EOpBitCount:
963 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
964 break;
965 case EOpFindLSB:
966 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
967 break;
968 case EOpFindMSB:
969 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
970 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300971 default:
972 setType(mOperand->getType());
973 mType.setQualifier(resultQualifier);
974 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400975 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300976}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400977
Olli Etuahob6fa0432016-09-28 16:28:05 +0100978TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
979 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
980 mOperand(operand),
981 mSwizzleOffsets(swizzleOffsets)
982{
983 ASSERT(mSwizzleOffsets.size() <= 4);
984 promote();
985}
986
Olli Etuahoa2234302016-08-31 12:05:39 +0300987TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
988 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
989{
990 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400991}
992
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300993TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
994 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
995{
996 promote();
997}
998
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000999TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1000 : TIntermNode(), mSymbol(symbol)
1001{
1002 ASSERT(symbol);
1003 setLine(line);
1004}
1005
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001006TIntermTernary::TIntermTernary(TIntermTyped *cond,
1007 TIntermTyped *trueExpression,
1008 TIntermTyped *falseExpression)
1009 : TIntermTyped(trueExpression->getType()),
1010 mCondition(cond),
1011 mTrueExpression(trueExpression),
1012 mFalseExpression(falseExpression)
1013{
1014 getTypePointer()->setQualifier(
1015 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1016}
1017
Olli Etuaho81629262017-04-19 11:56:01 +03001018TIntermLoop::TIntermLoop(TLoopType type,
1019 TIntermNode *init,
1020 TIntermTyped *cond,
1021 TIntermTyped *expr,
1022 TIntermBlock *body)
1023 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1024{
1025 // Declaration nodes with no children can appear if all the declarators just added constants to
1026 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1027 if (mInit && mInit->getAsDeclarationNode() &&
1028 mInit->getAsDeclarationNode()->getSequence()->empty())
1029 {
1030 mInit = nullptr;
1031 }
1032}
1033
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001034// static
1035TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1036 TIntermTyped *trueExpression,
1037 TIntermTyped *falseExpression)
1038{
1039 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1040 falseExpression->getQualifier() == EvqConst)
1041 {
1042 return EvqConst;
1043 }
1044 return EvqTemporary;
1045}
1046
Olli Etuahob6fa0432016-09-28 16:28:05 +01001047void TIntermSwizzle::promote()
1048{
1049 TQualifier resultQualifier = EvqTemporary;
1050 if (mOperand->getQualifier() == EvqConst)
1051 resultQualifier = EvqConst;
1052
1053 auto numFields = mSwizzleOffsets.size();
1054 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1055 static_cast<unsigned char>(numFields)));
1056}
1057
1058bool TIntermSwizzle::hasDuplicateOffsets() const
1059{
1060 int offsetCount[4] = {0u, 0u, 0u, 0u};
1061 for (const auto offset : mSwizzleOffsets)
1062 {
1063 offsetCount[offset]++;
1064 if (offsetCount[offset] > 1)
1065 {
1066 return true;
1067 }
1068 }
1069 return false;
1070}
1071
Olli Etuaho09b04a22016-12-15 13:30:26 +00001072bool TIntermSwizzle::offsetsMatch(int offset) const
1073{
1074 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1075}
1076
Olli Etuahob6fa0432016-09-28 16:28:05 +01001077void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1078{
1079 for (const int offset : mSwizzleOffsets)
1080 {
1081 switch (offset)
1082 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001083 case 0:
1084 *out << "x";
1085 break;
1086 case 1:
1087 *out << "y";
1088 break;
1089 case 2:
1090 *out << "z";
1091 break;
1092 case 3:
1093 *out << "w";
1094 break;
1095 default:
1096 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001097 }
1098 }
1099}
1100
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001101TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1102 const TIntermTyped *left,
1103 const TIntermTyped *right)
1104{
1105 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1106 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1107 right->getQualifier() != EvqConst)
1108 {
1109 return EvqTemporary;
1110 }
1111 return EvqConst;
1112}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001113
1114// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001115void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001116{
Olli Etuaho1dded802016-08-18 18:13:13 +03001117 ASSERT(!isMultiplication() ||
1118 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1119
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001120 // Comma is handled as a special case.
1121 if (mOp == EOpComma)
1122 {
1123 setType(mRight->getType());
1124 return;
1125 }
1126
Jamie Madillb1a85f42014-08-19 15:23:24 -04001127 // Base assumption: just make the type the same as the left
1128 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001129 setType(mLeft->getType());
1130
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001131 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001132 // Binary operations results in temporary variables unless both
1133 // operands are const.
1134 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1135 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001136 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001137 getTypePointer()->setQualifier(EvqTemporary);
1138 }
1139
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001140 // Handle indexing ops.
1141 switch (mOp)
1142 {
1143 case EOpIndexDirect:
1144 case EOpIndexIndirect:
1145 if (mLeft->isArray())
1146 {
1147 mType.clearArrayness();
1148 }
1149 else if (mLeft->isMatrix())
1150 {
1151 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1152 static_cast<unsigned char>(mLeft->getRows())));
1153 }
1154 else if (mLeft->isVector())
1155 {
1156 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1157 }
1158 else
1159 {
1160 UNREACHABLE();
1161 }
1162 return;
1163 case EOpIndexDirectStruct:
1164 {
1165 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1166 const int i = mRight->getAsConstantUnion()->getIConst(0);
1167 setType(*fields[i]->type());
1168 getTypePointer()->setQualifier(resultQualifier);
1169 return;
1170 }
1171 case EOpIndexDirectInterfaceBlock:
1172 {
1173 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1174 const int i = mRight->getAsConstantUnion()->getIConst(0);
1175 setType(*fields[i]->type());
1176 getTypePointer()->setQualifier(resultQualifier);
1177 return;
1178 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001179 default:
1180 break;
1181 }
1182
1183 ASSERT(mLeft->isArray() == mRight->isArray());
1184
1185 // The result gets promoted to the highest precision.
1186 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1187 getTypePointer()->setPrecision(higherPrecision);
1188
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001189 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001190
1191 //
1192 // All scalars or structs. Code after this test assumes this case is removed!
1193 //
1194 if (nominalSize == 1)
1195 {
1196 switch (mOp)
1197 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001198 //
1199 // Promote to conditional
1200 //
1201 case EOpEqual:
1202 case EOpNotEqual:
1203 case EOpLessThan:
1204 case EOpGreaterThan:
1205 case EOpLessThanEqual:
1206 case EOpGreaterThanEqual:
1207 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1208 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001209
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001210 //
1211 // And and Or operate on conditionals
1212 //
1213 case EOpLogicalAnd:
1214 case EOpLogicalXor:
1215 case EOpLogicalOr:
1216 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1217 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1218 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001219
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001220 default:
1221 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001222 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001223 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001224 }
1225
1226 // If we reach here, at least one of the operands is vector or matrix.
1227 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001228 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001229
Jamie Madillb1a85f42014-08-19 15:23:24 -04001230 switch (mOp)
1231 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001232 case EOpMul:
1233 break;
1234 case EOpMatrixTimesScalar:
1235 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001236 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001237 setType(TType(basicType, higherPrecision, resultQualifier,
1238 static_cast<unsigned char>(mRight->getCols()),
1239 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001240 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001241 break;
1242 case EOpMatrixTimesVector:
1243 setType(TType(basicType, higherPrecision, resultQualifier,
1244 static_cast<unsigned char>(mLeft->getRows()), 1));
1245 break;
1246 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001247 setType(TType(basicType, higherPrecision, resultQualifier,
1248 static_cast<unsigned char>(mRight->getCols()),
1249 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001250 break;
1251 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001252 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001253 static_cast<unsigned char>(nominalSize), 1));
1254 break;
1255 case EOpVectorTimesMatrix:
1256 setType(TType(basicType, higherPrecision, resultQualifier,
1257 static_cast<unsigned char>(mRight->getCols()), 1));
1258 break;
1259 case EOpMulAssign:
1260 case EOpVectorTimesScalarAssign:
1261 case EOpVectorTimesMatrixAssign:
1262 case EOpMatrixTimesScalarAssign:
1263 case EOpMatrixTimesMatrixAssign:
1264 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1265 break;
1266 case EOpAssign:
1267 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001268 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1269 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1270 break;
1271 case EOpAdd:
1272 case EOpSub:
1273 case EOpDiv:
1274 case EOpIMod:
1275 case EOpBitShiftLeft:
1276 case EOpBitShiftRight:
1277 case EOpBitwiseAnd:
1278 case EOpBitwiseXor:
1279 case EOpBitwiseOr:
1280 case EOpAddAssign:
1281 case EOpSubAssign:
1282 case EOpDivAssign:
1283 case EOpIModAssign:
1284 case EOpBitShiftLeftAssign:
1285 case EOpBitShiftRightAssign:
1286 case EOpBitwiseAndAssign:
1287 case EOpBitwiseXorAssign:
1288 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001289 {
1290 const int secondarySize =
1291 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1292 setType(TType(basicType, higherPrecision, resultQualifier,
1293 static_cast<unsigned char>(nominalSize),
1294 static_cast<unsigned char>(secondarySize)));
1295 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001296 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001297 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001298 case EOpEqual:
1299 case EOpNotEqual:
1300 case EOpLessThan:
1301 case EOpGreaterThan:
1302 case EOpLessThanEqual:
1303 case EOpGreaterThanEqual:
1304 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1305 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001306 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001307 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001308
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001309 case EOpIndexDirect:
1310 case EOpIndexIndirect:
1311 case EOpIndexDirectInterfaceBlock:
1312 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001313 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001314 UNREACHABLE();
1315 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001316 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001317 UNREACHABLE();
1318 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001319 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001320}
1321
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001322const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001323{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001324 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001325 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001326 ASSERT(index < static_cast<int>(getType().getArraySize()));
1327 TType arrayElementType = getType();
1328 arrayElementType.clearArrayness();
1329 size_t arrayElementSize = arrayElementType.getObjectSize();
1330 return &mUnionArrayPointer[arrayElementSize * index];
1331 }
1332 else if (isMatrix())
1333 {
1334 ASSERT(index < getType().getCols());
1335 int size = getType().getRows();
1336 return &mUnionArrayPointer[size * index];
1337 }
1338 else if (isVector())
1339 {
1340 ASSERT(index < getType().getNominalSize());
1341 return &mUnionArrayPointer[index];
1342 }
1343 else
1344 {
1345 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001346 return nullptr;
1347 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001348}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001349
Olli Etuahob6fa0432016-09-28 16:28:05 +01001350TIntermTyped *TIntermSwizzle::fold()
1351{
1352 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1353 if (operandConstant == nullptr)
1354 {
1355 return nullptr;
1356 }
1357
1358 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1359 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1360 {
1361 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1362 }
1363 return CreateFoldedNode(constArray, this, mType.getQualifier());
1364}
1365
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001366TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1367{
1368 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1369 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1370 switch (mOp)
1371 {
1372 case EOpIndexDirect:
1373 {
1374 if (leftConstant == nullptr || rightConstant == nullptr)
1375 {
1376 return nullptr;
1377 }
1378 int index = rightConstant->getIConst(0);
1379
1380 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1381 return CreateFoldedNode(constArray, this, mType.getQualifier());
1382 }
1383 case EOpIndexDirectStruct:
1384 {
1385 if (leftConstant == nullptr || rightConstant == nullptr)
1386 {
1387 return nullptr;
1388 }
1389 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1390 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1391
1392 size_t previousFieldsSize = 0;
1393 for (size_t i = 0; i < index; ++i)
1394 {
1395 previousFieldsSize += fields[i]->type()->getObjectSize();
1396 }
1397
1398 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1399 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1400 }
1401 case EOpIndexIndirect:
1402 case EOpIndexDirectInterfaceBlock:
1403 // Can never be constant folded.
1404 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001405 default:
1406 {
1407 if (leftConstant == nullptr || rightConstant == nullptr)
1408 {
1409 return nullptr;
1410 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001411 TConstantUnion *constArray =
1412 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001413
1414 // Nodes may be constant folded without being qualified as constant.
1415 return CreateFoldedNode(constArray, this, mType.getQualifier());
1416 }
1417 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001418}
1419
Olli Etuahof119a262016-08-19 15:54:22 +03001420TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001421{
1422 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1423 if (operandConstant == nullptr)
1424 {
1425 return nullptr;
1426 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301427
1428 TConstantUnion *constArray = nullptr;
1429 switch (mOp)
1430 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001431 case EOpAny:
1432 case EOpAll:
1433 case EOpLength:
1434 case EOpTranspose:
1435 case EOpDeterminant:
1436 case EOpInverse:
1437 case EOpPackSnorm2x16:
1438 case EOpUnpackSnorm2x16:
1439 case EOpPackUnorm2x16:
1440 case EOpUnpackUnorm2x16:
1441 case EOpPackHalf2x16:
1442 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001443 case EOpPackUnorm4x8:
1444 case EOpPackSnorm4x8:
1445 case EOpUnpackUnorm4x8:
1446 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001447 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1448 break;
1449 default:
1450 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1451 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301452 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001453
1454 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001455 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001456}
1457
Olli Etuahof119a262016-08-19 15:54:22 +03001458TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001459{
1460 // Make sure that all params are constant before actual constant folding.
1461 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001462 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001463 if (param->getAsConstantUnion() == nullptr)
1464 {
1465 return nullptr;
1466 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001467 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001468 TConstantUnion *constArray = nullptr;
1469 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001470 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001471 else
Olli Etuahof119a262016-08-19 15:54:22 +03001472 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001473
1474 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001475 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001476}
1477
Jamie Madillb1a85f42014-08-19 15:23:24 -04001478//
1479// The fold functions see if an operation on a constant can be done in place,
1480// without generating run-time code.
1481//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001482// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001483//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001484TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1485 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001486 TDiagnostics *diagnostics,
1487 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001488{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001489 const TConstantUnion *leftArray = getUnionArrayPointer();
1490 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001491
Olli Etuahof119a262016-08-19 15:54:22 +03001492 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001493
1494 size_t objectSize = getType().getObjectSize();
1495
1496 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1497 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1498 {
1499 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1500 }
1501 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1502 {
1503 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001504 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001505 objectSize = rightNode->getType().getObjectSize();
1506 }
1507
1508 TConstantUnion *resultArray = nullptr;
1509
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001510 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001511 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001512 case EOpAdd:
1513 resultArray = new TConstantUnion[objectSize];
1514 for (size_t i = 0; i < objectSize; i++)
1515 resultArray[i] =
1516 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1517 break;
1518 case EOpSub:
1519 resultArray = new TConstantUnion[objectSize];
1520 for (size_t i = 0; i < objectSize; i++)
1521 resultArray[i] =
1522 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1523 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001524
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001525 case EOpMul:
1526 case EOpVectorTimesScalar:
1527 case EOpMatrixTimesScalar:
1528 resultArray = new TConstantUnion[objectSize];
1529 for (size_t i = 0; i < objectSize; i++)
1530 resultArray[i] =
1531 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1532 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001533
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001534 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001535 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001536 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001537 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001538
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001539 const int leftCols = getCols();
1540 const int leftRows = getRows();
1541 const int rightCols = rightNode->getType().getCols();
1542 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001543 const int resultCols = rightCols;
1544 const int resultRows = leftRows;
1545
1546 resultArray = new TConstantUnion[resultCols * resultRows];
1547 for (int row = 0; row < resultRows; row++)
1548 {
1549 for (int column = 0; column < resultCols; column++)
1550 {
1551 resultArray[resultRows * column + row].setFConst(0.0f);
1552 for (int i = 0; i < leftCols; i++)
1553 {
1554 resultArray[resultRows * column + row].setFConst(
1555 resultArray[resultRows * column + row].getFConst() +
1556 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001557 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001558 }
1559 }
1560 }
1561 }
1562 break;
1563
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001564 case EOpDiv:
1565 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001566 {
1567 resultArray = new TConstantUnion[objectSize];
1568 for (size_t i = 0; i < objectSize; i++)
1569 {
1570 switch (getType().getBasicType())
1571 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001572 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001573 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001574 ASSERT(op == EOpDiv);
1575 float dividend = leftArray[i].getFConst();
1576 float divisor = rightArray[i].getFConst();
1577 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001578 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001579 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001580 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001581 diagnostics->warning(
1582 getLine(),
1583 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001584 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001585 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001586 }
1587 else
1588 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001589 diagnostics->warning(getLine(),
1590 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001591 bool negativeResult =
1592 std::signbit(dividend) != std::signbit(divisor);
1593 resultArray[i].setFConst(
1594 negativeResult ? -std::numeric_limits<float>::infinity()
1595 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001596 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001597 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001598 else if (gl::isInf(dividend) && gl::isInf(divisor))
1599 {
1600 diagnostics->warning(getLine(),
1601 "Infinity divided by infinity during constant "
1602 "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());
1605 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001606 else
1607 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001608 float result = dividend / divisor;
1609 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001610 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001611 diagnostics->warning(
1612 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001613 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001614 }
1615 resultArray[i].setFConst(result);
1616 }
1617 break;
1618 }
1619 case EbtInt:
1620 if (rightArray[i] == 0)
1621 {
1622 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001623 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001624 resultArray[i].setIConst(INT_MAX);
1625 }
1626 else
1627 {
1628 int lhs = leftArray[i].getIConst();
1629 int divisor = rightArray[i].getIConst();
1630 if (op == EOpDiv)
1631 {
1632 // Check for the special case where the minimum representable number
1633 // is
1634 // divided by -1. If left alone this leads to integer overflow in
1635 // C++.
1636 // ESSL 3.00.6 section 4.1.3 Integers:
1637 // "However, for the case where the minimum representable value is
1638 // divided by -1, it is allowed to return either the minimum
1639 // representable value or the maximum representable value."
1640 if (lhs == -0x7fffffff - 1 && divisor == -1)
1641 {
1642 resultArray[i].setIConst(0x7fffffff);
1643 }
1644 else
1645 {
1646 resultArray[i].setIConst(lhs / divisor);
1647 }
Olli Etuahod4453572016-09-27 13:21:46 +01001648 }
1649 else
1650 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001651 ASSERT(op == EOpIMod);
1652 if (lhs < 0 || divisor < 0)
1653 {
1654 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1655 // when
1656 // either one of the operands is negative.
1657 diagnostics->warning(getLine(),
1658 "Negative modulus operator operand "
1659 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001660 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001661 resultArray[i].setIConst(0);
1662 }
1663 else
1664 {
1665 resultArray[i].setIConst(lhs % divisor);
1666 }
Olli Etuahod4453572016-09-27 13:21:46 +01001667 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001668 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001669 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001670
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001671 case EbtUInt:
1672 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001673 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001674 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001675 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001676 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001677 }
1678 else
1679 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001680 if (op == EOpDiv)
1681 {
1682 resultArray[i].setUConst(leftArray[i].getUConst() /
1683 rightArray[i].getUConst());
1684 }
1685 else
1686 {
1687 ASSERT(op == EOpIMod);
1688 resultArray[i].setUConst(leftArray[i].getUConst() %
1689 rightArray[i].getUConst());
1690 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001691 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001692 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001693
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001694 default:
1695 UNREACHABLE();
1696 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001697 }
1698 }
1699 }
1700 break;
1701
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001702 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001703 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001704 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001705 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001706
1707 const int matrixCols = getCols();
1708 const int matrixRows = getRows();
1709
1710 resultArray = new TConstantUnion[matrixRows];
1711
1712 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1713 {
1714 resultArray[matrixRow].setFConst(0.0f);
1715 for (int col = 0; col < matrixCols; col++)
1716 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001717 resultArray[matrixRow].setFConst(
1718 resultArray[matrixRow].getFConst() +
1719 leftArray[col * matrixRows + matrixRow].getFConst() *
1720 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001721 }
1722 }
1723 }
1724 break;
1725
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001726 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001727 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001728 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001729 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001730
1731 const int matrixCols = rightNode->getType().getCols();
1732 const int matrixRows = rightNode->getType().getRows();
1733
1734 resultArray = new TConstantUnion[matrixCols];
1735
1736 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1737 {
1738 resultArray[matrixCol].setFConst(0.0f);
1739 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1740 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001741 resultArray[matrixCol].setFConst(
1742 resultArray[matrixCol].getFConst() +
1743 leftArray[matrixRow].getFConst() *
1744 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001745 }
1746 }
1747 }
1748 break;
1749
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001750 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001751 {
1752 resultArray = new TConstantUnion[objectSize];
1753 for (size_t i = 0; i < objectSize; i++)
1754 {
1755 resultArray[i] = leftArray[i] && rightArray[i];
1756 }
1757 }
1758 break;
1759
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001760 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001761 {
1762 resultArray = new TConstantUnion[objectSize];
1763 for (size_t i = 0; i < objectSize; i++)
1764 {
1765 resultArray[i] = leftArray[i] || rightArray[i];
1766 }
1767 }
1768 break;
1769
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001770 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001771 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001772 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001773 resultArray = new TConstantUnion[objectSize];
1774 for (size_t i = 0; i < objectSize; i++)
1775 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001776 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001777 }
1778 }
1779 break;
1780
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001781 case EOpBitwiseAnd:
1782 resultArray = new TConstantUnion[objectSize];
1783 for (size_t i = 0; i < objectSize; i++)
1784 resultArray[i] = leftArray[i] & rightArray[i];
1785 break;
1786 case EOpBitwiseXor:
1787 resultArray = new TConstantUnion[objectSize];
1788 for (size_t i = 0; i < objectSize; i++)
1789 resultArray[i] = leftArray[i] ^ rightArray[i];
1790 break;
1791 case EOpBitwiseOr:
1792 resultArray = new TConstantUnion[objectSize];
1793 for (size_t i = 0; i < objectSize; i++)
1794 resultArray[i] = leftArray[i] | rightArray[i];
1795 break;
1796 case EOpBitShiftLeft:
1797 resultArray = new TConstantUnion[objectSize];
1798 for (size_t i = 0; i < objectSize; i++)
1799 resultArray[i] =
1800 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1801 break;
1802 case EOpBitShiftRight:
1803 resultArray = new TConstantUnion[objectSize];
1804 for (size_t i = 0; i < objectSize; i++)
1805 resultArray[i] =
1806 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1807 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001808
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001809 case EOpLessThan:
1810 ASSERT(objectSize == 1);
1811 resultArray = new TConstantUnion[1];
1812 resultArray->setBConst(*leftArray < *rightArray);
1813 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001814
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001815 case EOpGreaterThan:
1816 ASSERT(objectSize == 1);
1817 resultArray = new TConstantUnion[1];
1818 resultArray->setBConst(*leftArray > *rightArray);
1819 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001820
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001821 case EOpLessThanEqual:
1822 ASSERT(objectSize == 1);
1823 resultArray = new TConstantUnion[1];
1824 resultArray->setBConst(!(*leftArray > *rightArray));
1825 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001826
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001827 case EOpGreaterThanEqual:
1828 ASSERT(objectSize == 1);
1829 resultArray = new TConstantUnion[1];
1830 resultArray->setBConst(!(*leftArray < *rightArray));
1831 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001832
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001833 case EOpEqual:
1834 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001835 {
1836 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001837 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001838 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001839 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001840 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001841 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001842 equal = false;
1843 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001844 }
1845 }
1846 if (op == EOpEqual)
1847 {
1848 resultArray->setBConst(equal);
1849 }
1850 else
1851 {
1852 resultArray->setBConst(!equal);
1853 }
1854 }
1855 break;
1856
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001857 default:
1858 UNREACHABLE();
1859 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001860 }
1861 return resultArray;
1862}
1863
Olli Etuahof119a262016-08-19 15:54:22 +03001864// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1865// code. Returns the constant value to keep using. Nullptr should not be returned.
1866TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001867{
Olli Etuahof119a262016-08-19 15:54:22 +03001868 // Do operations where the return type may have a different number of components compared to the
1869 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001870
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001871 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001872 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301873
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001874 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301875 TConstantUnion *resultArray = nullptr;
1876 switch (op)
1877 {
Olli Etuahof119a262016-08-19 15:54:22 +03001878 case EOpAny:
1879 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301880 resultArray = new TConstantUnion();
1881 resultArray->setBConst(false);
1882 for (size_t i = 0; i < objectSize; i++)
1883 {
1884 if (operandArray[i].getBConst())
1885 {
1886 resultArray->setBConst(true);
1887 break;
1888 }
1889 }
1890 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301891
Olli Etuahof119a262016-08-19 15:54:22 +03001892 case EOpAll:
1893 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301894 resultArray = new TConstantUnion();
1895 resultArray->setBConst(true);
1896 for (size_t i = 0; i < objectSize; i++)
1897 {
1898 if (!operandArray[i].getBConst())
1899 {
1900 resultArray->setBConst(false);
1901 break;
1902 }
1903 }
1904 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301905
Olli Etuahof119a262016-08-19 15:54:22 +03001906 case EOpLength:
1907 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301908 resultArray = new TConstantUnion();
1909 resultArray->setFConst(VectorLength(operandArray, objectSize));
1910 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301911
Olli Etuahof119a262016-08-19 15:54:22 +03001912 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301913 {
Olli Etuahof119a262016-08-19 15:54:22 +03001914 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301915 resultArray = new TConstantUnion[objectSize];
1916 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001917 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301918 SetUnionArrayFromMatrix(result, resultArray);
1919 break;
1920 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301921
Olli Etuahof119a262016-08-19 15:54:22 +03001922 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301923 {
Olli Etuahof119a262016-08-19 15:54:22 +03001924 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301925 unsigned int size = getType().getNominalSize();
1926 ASSERT(size >= 2 && size <= 4);
1927 resultArray = new TConstantUnion();
1928 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1929 break;
1930 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301931
Olli Etuahof119a262016-08-19 15:54:22 +03001932 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301933 {
Olli Etuahof119a262016-08-19 15:54:22 +03001934 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301935 unsigned int size = getType().getNominalSize();
1936 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001937 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301938 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1939 SetUnionArrayFromMatrix(result, resultArray);
1940 break;
1941 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301942
Olli Etuahof119a262016-08-19 15:54:22 +03001943 case EOpPackSnorm2x16:
1944 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945 ASSERT(getType().getNominalSize() == 2);
1946 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001947 resultArray->setUConst(
1948 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301949 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301950
Olli Etuahof119a262016-08-19 15:54:22 +03001951 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301952 {
Olli Etuahof119a262016-08-19 15:54:22 +03001953 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301954 resultArray = new TConstantUnion[2];
1955 float f1, f2;
1956 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1957 resultArray[0].setFConst(f1);
1958 resultArray[1].setFConst(f2);
1959 break;
1960 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301961
Olli Etuahof119a262016-08-19 15:54:22 +03001962 case EOpPackUnorm2x16:
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::packUnorm2x16(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 EOpUnpackUnorm2x16:
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::unpackUnorm2x16(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 EOpPackHalf2x16:
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::packHalf2x16(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 EOpUnpackHalf2x16:
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::unpackHalf2x16(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 Etuaho25aef452017-01-29 16:15:44 -08002000 case EOpPackUnorm4x8:
2001 {
2002 ASSERT(getType().getBasicType() == EbtFloat);
2003 resultArray = new TConstantUnion();
2004 resultArray->setUConst(
2005 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2006 operandArray[2].getFConst(), operandArray[3].getFConst()));
2007 break;
2008 }
2009 case EOpPackSnorm4x8:
2010 {
2011 ASSERT(getType().getBasicType() == EbtFloat);
2012 resultArray = new TConstantUnion();
2013 resultArray->setUConst(
2014 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2015 operandArray[2].getFConst(), operandArray[3].getFConst()));
2016 break;
2017 }
2018 case EOpUnpackUnorm4x8:
2019 {
2020 ASSERT(getType().getBasicType() == EbtUInt);
2021 resultArray = new TConstantUnion[4];
2022 float f[4];
2023 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2024 for (size_t i = 0; i < 4; ++i)
2025 {
2026 resultArray[i].setFConst(f[i]);
2027 }
2028 break;
2029 }
2030 case EOpUnpackSnorm4x8:
2031 {
2032 ASSERT(getType().getBasicType() == EbtUInt);
2033 resultArray = new TConstantUnion[4];
2034 float f[4];
2035 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2036 for (size_t i = 0; i < 4; ++i)
2037 {
2038 resultArray[i].setFConst(f[i]);
2039 }
2040 break;
2041 }
2042
Olli Etuahof119a262016-08-19 15:54:22 +03002043 default:
2044 UNREACHABLE();
2045 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302046 }
2047
2048 return resultArray;
2049}
2050
Olli Etuahof119a262016-08-19 15:54:22 +03002051TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2052 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302053{
Olli Etuahof119a262016-08-19 15:54:22 +03002054 // Do unary operations where each component of the result is computed based on the corresponding
2055 // component of the operand. Also folds normalize, though the divisor in that case takes all
2056 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302057
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002058 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002059 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002060
2061 size_t objectSize = getType().getObjectSize();
2062
Arun Patoleab2b9a22015-07-06 18:27:56 +05302063 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2064 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302065 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002066 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302067 {
Olli Etuahof119a262016-08-19 15:54:22 +03002068 case EOpNegative:
2069 switch (getType().getBasicType())
2070 {
2071 case EbtFloat:
2072 resultArray[i].setFConst(-operandArray[i].getFConst());
2073 break;
2074 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002075 if (operandArray[i] == std::numeric_limits<int>::min())
2076 {
2077 // The minimum representable integer doesn't have a positive
2078 // counterpart, rather the negation overflows and in ESSL is supposed to
2079 // wrap back to the minimum representable integer. Make sure that we
2080 // don't actually let the negation overflow, which has undefined
2081 // behavior in C++.
2082 resultArray[i].setIConst(std::numeric_limits<int>::min());
2083 }
2084 else
2085 {
2086 resultArray[i].setIConst(-operandArray[i].getIConst());
2087 }
Olli Etuahof119a262016-08-19 15:54:22 +03002088 break;
2089 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002090 if (operandArray[i] == 0x80000000u)
2091 {
2092 resultArray[i].setUConst(0x80000000u);
2093 }
2094 else
2095 {
2096 resultArray[i].setUConst(static_cast<unsigned int>(
2097 -static_cast<int>(operandArray[i].getUConst())));
2098 }
Olli Etuahof119a262016-08-19 15:54:22 +03002099 break;
2100 default:
2101 UNREACHABLE();
2102 return nullptr;
2103 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302104 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302105
Olli Etuahof119a262016-08-19 15:54:22 +03002106 case EOpPositive:
2107 switch (getType().getBasicType())
2108 {
2109 case EbtFloat:
2110 resultArray[i].setFConst(operandArray[i].getFConst());
2111 break;
2112 case EbtInt:
2113 resultArray[i].setIConst(operandArray[i].getIConst());
2114 break;
2115 case EbtUInt:
2116 resultArray[i].setUConst(static_cast<unsigned int>(
2117 static_cast<int>(operandArray[i].getUConst())));
2118 break;
2119 default:
2120 UNREACHABLE();
2121 return nullptr;
2122 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302123 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302124
Olli Etuahof119a262016-08-19 15:54:22 +03002125 case EOpLogicalNot:
2126 switch (getType().getBasicType())
2127 {
2128 case EbtBool:
2129 resultArray[i].setBConst(!operandArray[i].getBConst());
2130 break;
2131 default:
2132 UNREACHABLE();
2133 return nullptr;
2134 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302135 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136
Olli Etuahof119a262016-08-19 15:54:22 +03002137 case EOpBitwiseNot:
2138 switch (getType().getBasicType())
2139 {
2140 case EbtInt:
2141 resultArray[i].setIConst(~operandArray[i].getIConst());
2142 break;
2143 case EbtUInt:
2144 resultArray[i].setUConst(~operandArray[i].getUConst());
2145 break;
2146 default:
2147 UNREACHABLE();
2148 return nullptr;
2149 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302150 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302151
Olli Etuahof119a262016-08-19 15:54:22 +03002152 case EOpRadians:
2153 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302154 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2155 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302156
Olli Etuahof119a262016-08-19 15:54:22 +03002157 case EOpDegrees:
2158 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302159 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2160 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302161
Olli Etuahof119a262016-08-19 15:54:22 +03002162 case EOpSin:
2163 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302164 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302165
Olli Etuahof119a262016-08-19 15:54:22 +03002166 case EOpCos:
2167 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2168 break;
2169
2170 case EOpTan:
2171 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2172 break;
2173
2174 case EOpAsin:
2175 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2176 // 0.
2177 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2178 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2179 diagnostics, &resultArray[i]);
2180 else
2181 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2182 break;
2183
2184 case EOpAcos:
2185 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2186 // 0.
2187 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2188 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2189 diagnostics, &resultArray[i]);
2190 else
2191 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2192 break;
2193
2194 case EOpAtan:
2195 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2196 break;
2197
2198 case EOpSinh:
2199 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2200 break;
2201
2202 case EOpCosh:
2203 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2204 break;
2205
2206 case EOpTanh:
2207 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2208 break;
2209
2210 case EOpAsinh:
2211 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2212 break;
2213
2214 case EOpAcosh:
2215 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2216 if (operandArray[i].getFConst() < 1.0f)
2217 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2218 diagnostics, &resultArray[i]);
2219 else
2220 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2221 break;
2222
2223 case EOpAtanh:
2224 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2225 // 0.
2226 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2227 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2228 diagnostics, &resultArray[i]);
2229 else
2230 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2231 break;
2232
2233 case EOpAbs:
2234 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302235 {
Olli Etuahof119a262016-08-19 15:54:22 +03002236 case EbtFloat:
2237 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2238 break;
2239 case EbtInt:
2240 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2241 break;
2242 default:
2243 UNREACHABLE();
2244 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302245 }
2246 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002247
2248 case EOpSign:
2249 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302250 {
Olli Etuahof119a262016-08-19 15:54:22 +03002251 case EbtFloat:
2252 {
2253 float fConst = operandArray[i].getFConst();
2254 float fResult = 0.0f;
2255 if (fConst > 0.0f)
2256 fResult = 1.0f;
2257 else if (fConst < 0.0f)
2258 fResult = -1.0f;
2259 resultArray[i].setFConst(fResult);
2260 break;
2261 }
2262 case EbtInt:
2263 {
2264 int iConst = operandArray[i].getIConst();
2265 int iResult = 0;
2266 if (iConst > 0)
2267 iResult = 1;
2268 else if (iConst < 0)
2269 iResult = -1;
2270 resultArray[i].setIConst(iResult);
2271 break;
2272 }
2273 default:
2274 UNREACHABLE();
2275 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302276 }
2277 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302278
Olli Etuahof119a262016-08-19 15:54:22 +03002279 case EOpFloor:
2280 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2281 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302282
Olli Etuahof119a262016-08-19 15:54:22 +03002283 case EOpTrunc:
2284 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2285 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302286
Olli Etuahof119a262016-08-19 15:54:22 +03002287 case EOpRound:
2288 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2289 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302290
Olli Etuahof119a262016-08-19 15:54:22 +03002291 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302292 {
Olli Etuahof119a262016-08-19 15:54:22 +03002293 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302294 float x = operandArray[i].getFConst();
2295 float result;
2296 float fractPart = modff(x, &result);
2297 if (fabsf(fractPart) == 0.5f)
2298 result = 2.0f * roundf(x / 2.0f);
2299 else
2300 result = roundf(x);
2301 resultArray[i].setFConst(result);
2302 break;
2303 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302304
Olli Etuahof119a262016-08-19 15:54:22 +03002305 case EOpCeil:
2306 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2307 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302308
Olli Etuahof119a262016-08-19 15:54:22 +03002309 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302310 {
Olli Etuahof119a262016-08-19 15:54:22 +03002311 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302312 float x = operandArray[i].getFConst();
2313 resultArray[i].setFConst(x - floorf(x));
2314 break;
2315 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302316
Olli Etuahof119a262016-08-19 15:54:22 +03002317 case EOpIsNan:
2318 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302319 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2320 break;
Arun Patole551279e2015-07-07 18:18:23 +05302321
Olli Etuahof119a262016-08-19 15:54:22 +03002322 case EOpIsInf:
2323 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302324 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2325 break;
Arun Patole551279e2015-07-07 18:18:23 +05302326
Olli Etuahof119a262016-08-19 15:54:22 +03002327 case EOpFloatBitsToInt:
2328 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302329 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2330 break;
Arun Patole551279e2015-07-07 18:18:23 +05302331
Olli Etuahof119a262016-08-19 15:54:22 +03002332 case EOpFloatBitsToUint:
2333 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302334 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2335 break;
Arun Patole551279e2015-07-07 18:18:23 +05302336
Olli Etuahof119a262016-08-19 15:54:22 +03002337 case EOpIntBitsToFloat:
2338 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302339 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2340 break;
Arun Patole551279e2015-07-07 18:18:23 +05302341
Olli Etuahof119a262016-08-19 15:54:22 +03002342 case EOpUintBitsToFloat:
2343 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302344 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2345 break;
Arun Patole551279e2015-07-07 18:18:23 +05302346
Olli Etuahof119a262016-08-19 15:54:22 +03002347 case EOpExp:
2348 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2349 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302350
Olli Etuahof119a262016-08-19 15:54:22 +03002351 case EOpLog:
2352 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2353 if (operandArray[i].getFConst() <= 0.0f)
2354 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2355 diagnostics, &resultArray[i]);
2356 else
2357 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2358 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302359
Olli Etuahof119a262016-08-19 15:54:22 +03002360 case EOpExp2:
2361 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2362 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302363
Olli Etuahof119a262016-08-19 15:54:22 +03002364 case EOpLog2:
2365 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2366 // And log2f is not available on some plarforms like old android, so just using
2367 // log(x)/log(2) here.
2368 if (operandArray[i].getFConst() <= 0.0f)
2369 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2370 diagnostics, &resultArray[i]);
2371 else
2372 {
2373 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2374 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2375 }
2376 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302377
Olli Etuahof119a262016-08-19 15:54:22 +03002378 case EOpSqrt:
2379 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2380 if (operandArray[i].getFConst() < 0.0f)
2381 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2382 diagnostics, &resultArray[i]);
2383 else
2384 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2385 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302386
Olli Etuahof119a262016-08-19 15:54:22 +03002387 case EOpInverseSqrt:
2388 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2389 // so getting the square root first using builtin function sqrt() and then taking
2390 // its inverse.
2391 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2392 // result to 0.
2393 if (operandArray[i].getFConst() <= 0.0f)
2394 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2395 diagnostics, &resultArray[i]);
2396 else
2397 {
2398 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2399 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2400 }
2401 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302402
Olli Etuahod68924e2017-01-02 17:34:40 +00002403 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002404 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302405 resultArray[i].setBConst(!operandArray[i].getBConst());
2406 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302407
Olli Etuahof119a262016-08-19 15:54:22 +03002408 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302409 {
Olli Etuahof119a262016-08-19 15:54:22 +03002410 ASSERT(getType().getBasicType() == EbtFloat);
2411 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302412 float length = VectorLength(operandArray, objectSize);
2413 if (length)
2414 resultArray[i].setFConst(x / length);
2415 else
Olli Etuahof119a262016-08-19 15:54:22 +03002416 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2417 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302418 break;
2419 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002420 case EOpBitfieldReverse:
2421 {
2422 uint32_t value;
2423 if (getType().getBasicType() == EbtInt)
2424 {
2425 value = static_cast<uint32_t>(operandArray[i].getIConst());
2426 }
2427 else
2428 {
2429 ASSERT(getType().getBasicType() == EbtUInt);
2430 value = operandArray[i].getUConst();
2431 }
2432 uint32_t result = gl::BitfieldReverse(value);
2433 if (getType().getBasicType() == EbtInt)
2434 {
2435 resultArray[i].setIConst(static_cast<int32_t>(result));
2436 }
2437 else
2438 {
2439 resultArray[i].setUConst(result);
2440 }
2441 break;
2442 }
2443 case EOpBitCount:
2444 {
2445 uint32_t value;
2446 if (getType().getBasicType() == EbtInt)
2447 {
2448 value = static_cast<uint32_t>(operandArray[i].getIConst());
2449 }
2450 else
2451 {
2452 ASSERT(getType().getBasicType() == EbtUInt);
2453 value = operandArray[i].getUConst();
2454 }
2455 int result = gl::BitCount(value);
2456 resultArray[i].setIConst(result);
2457 break;
2458 }
2459 case EOpFindLSB:
2460 {
2461 uint32_t value;
2462 if (getType().getBasicType() == EbtInt)
2463 {
2464 value = static_cast<uint32_t>(operandArray[i].getIConst());
2465 }
2466 else
2467 {
2468 ASSERT(getType().getBasicType() == EbtUInt);
2469 value = operandArray[i].getUConst();
2470 }
2471 resultArray[i].setIConst(gl::FindLSB(value));
2472 break;
2473 }
2474 case EOpFindMSB:
2475 {
2476 uint32_t value;
2477 if (getType().getBasicType() == EbtInt)
2478 {
2479 int intValue = operandArray[i].getIConst();
2480 value = static_cast<uint32_t>(intValue);
2481 if (intValue < 0)
2482 {
2483 // Look for zero instead of one in value. This also handles the intValue ==
2484 // -1 special case, where the return value needs to be -1.
2485 value = ~value;
2486 }
2487 }
2488 else
2489 {
2490 ASSERT(getType().getBasicType() == EbtUInt);
2491 value = operandArray[i].getUConst();
2492 }
2493 resultArray[i].setIConst(gl::FindMSB(value));
2494 break;
2495 }
Olli Etuahof119a262016-08-19 15:54:22 +03002496 case EOpDFdx:
2497 case EOpDFdy:
2498 case EOpFwidth:
2499 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302500 // Derivatives of constant arguments should be 0.
2501 resultArray[i].setFConst(0.0f);
2502 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302503
Olli Etuahof119a262016-08-19 15:54:22 +03002504 default:
2505 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302506 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302507 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002508
Arun Patoleab2b9a22015-07-06 18:27:56 +05302509 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002510}
2511
Olli Etuahof119a262016-08-19 15:54:22 +03002512void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2513 FloatTypeUnaryFunc builtinFunc,
2514 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302515{
2516 ASSERT(builtinFunc);
2517
Olli Etuahof119a262016-08-19 15:54:22 +03002518 ASSERT(getType().getBasicType() == EbtFloat);
2519 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302520}
2521
Jamie Madillb1a85f42014-08-19 15:23:24 -04002522// static
Olli Etuahof119a262016-08-19 15:54:22 +03002523TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002524{
2525 ASSERT(aggregate->getSequence()->size() > 0u);
2526 size_t resultSize = aggregate->getType().getObjectSize();
2527 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2528 TBasicType basicType = aggregate->getBasicType();
2529
2530 size_t resultIndex = 0u;
2531
2532 if (aggregate->getSequence()->size() == 1u)
2533 {
2534 TIntermNode *argument = aggregate->getSequence()->front();
2535 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2536 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2537 // Check the special case of constructing a matrix diagonal from a single scalar,
2538 // or a vector from a single scalar.
2539 if (argumentConstant->getType().getObjectSize() == 1u)
2540 {
2541 if (aggregate->isMatrix())
2542 {
2543 int resultCols = aggregate->getType().getCols();
2544 int resultRows = aggregate->getType().getRows();
2545 for (int col = 0; col < resultCols; ++col)
2546 {
2547 for (int row = 0; row < resultRows; ++row)
2548 {
2549 if (col == row)
2550 {
2551 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2552 }
2553 else
2554 {
2555 resultArray[resultIndex].setFConst(0.0f);
2556 }
2557 ++resultIndex;
2558 }
2559 }
2560 }
2561 else
2562 {
2563 while (resultIndex < resultSize)
2564 {
2565 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2566 ++resultIndex;
2567 }
2568 }
2569 ASSERT(resultIndex == resultSize);
2570 return resultArray;
2571 }
2572 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2573 {
2574 // The special case of constructing a matrix from a matrix.
2575 int argumentCols = argumentConstant->getType().getCols();
2576 int argumentRows = argumentConstant->getType().getRows();
2577 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002578 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002579 for (int col = 0; col < resultCols; ++col)
2580 {
2581 for (int row = 0; row < resultRows; ++row)
2582 {
2583 if (col < argumentCols && row < argumentRows)
2584 {
2585 resultArray[resultIndex].cast(basicType,
2586 argumentUnionArray[col * argumentRows + row]);
2587 }
2588 else if (col == row)
2589 {
2590 resultArray[resultIndex].setFConst(1.0f);
2591 }
2592 else
2593 {
2594 resultArray[resultIndex].setFConst(0.0f);
2595 }
2596 ++resultIndex;
2597 }
2598 }
2599 ASSERT(resultIndex == resultSize);
2600 return resultArray;
2601 }
2602 }
2603
2604 for (TIntermNode *&argument : *aggregate->getSequence())
2605 {
2606 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2607 size_t argumentSize = argumentConstant->getType().getObjectSize();
2608 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2609 for (size_t i = 0u; i < argumentSize; ++i)
2610 {
2611 if (resultIndex >= resultSize)
2612 break;
2613 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2614 ++resultIndex;
2615 }
2616 }
2617 ASSERT(resultIndex == resultSize);
2618 return resultArray;
2619}
2620
2621// static
Olli Etuahof119a262016-08-19 15:54:22 +03002622TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2623 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302624{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002625 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002626 TIntermSequence *arguments = aggregate->getSequence();
2627 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2628 std::vector<const TConstantUnion *> unionArrays(argsCount);
2629 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002630 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302631 TBasicType basicType = EbtVoid;
2632 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002633 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302634 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002635 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2636 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302637
2638 if (i == 0)
2639 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002640 basicType = argConstant->getType().getBasicType();
2641 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302642 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002643 unionArrays[i] = argConstant->getUnionArrayPointer();
2644 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002645 if (objectSizes[i] > maxObjectSize)
2646 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302647 }
2648
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002649 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302650 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002651 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302652 if (objectSizes[i] != maxObjectSize)
2653 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2654 }
Arun Patole274f0702015-05-05 13:33:30 +05302655
Olli Etuahob43846e2015-06-02 18:18:57 +03002656 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002657
2658 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302659 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002660 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302661 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002662 ASSERT(basicType == EbtFloat);
2663 resultArray = new TConstantUnion[maxObjectSize];
2664 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302665 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002666 float y = unionArrays[0][i].getFConst();
2667 float x = unionArrays[1][i].getFConst();
2668 // Results are undefined if x and y are both 0.
2669 if (x == 0.0f && y == 0.0f)
2670 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2671 else
2672 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302673 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002674 break;
2675 }
Arun Patolebf790422015-05-18 17:53:04 +05302676
Olli Etuaho51182ab2017-01-22 00:12:29 +00002677 case EOpPow:
2678 {
2679 ASSERT(basicType == EbtFloat);
2680 resultArray = new TConstantUnion[maxObjectSize];
2681 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302682 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002683 float x = unionArrays[0][i].getFConst();
2684 float y = unionArrays[1][i].getFConst();
2685 // Results are undefined if x < 0.
2686 // Results are undefined if x = 0 and y <= 0.
2687 if (x < 0.0f)
2688 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2689 else if (x == 0.0f && y <= 0.0f)
2690 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2691 else
2692 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302693 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002694 break;
2695 }
Arun Patolebf790422015-05-18 17:53:04 +05302696
Olli Etuaho51182ab2017-01-22 00:12:29 +00002697 case EOpMod:
2698 {
2699 ASSERT(basicType == EbtFloat);
2700 resultArray = new TConstantUnion[maxObjectSize];
2701 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302702 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002703 float x = unionArrays[0][i].getFConst();
2704 float y = unionArrays[1][i].getFConst();
2705 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302706 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002707 break;
2708 }
Arun Patolebf790422015-05-18 17:53:04 +05302709
Olli Etuaho51182ab2017-01-22 00:12:29 +00002710 case EOpMin:
2711 {
2712 resultArray = new TConstantUnion[maxObjectSize];
2713 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302714 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002715 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302716 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002717 case EbtFloat:
2718 resultArray[i].setFConst(
2719 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2720 break;
2721 case EbtInt:
2722 resultArray[i].setIConst(
2723 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2724 break;
2725 case EbtUInt:
2726 resultArray[i].setUConst(
2727 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2728 break;
2729 default:
2730 UNREACHABLE();
2731 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302732 }
2733 }
2734 break;
Arun Patole274f0702015-05-05 13:33:30 +05302735 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002736
2737 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302738 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002739 resultArray = new TConstantUnion[maxObjectSize];
2740 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302741 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002742 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302743 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002744 case EbtFloat:
2745 resultArray[i].setFConst(
2746 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2747 break;
2748 case EbtInt:
2749 resultArray[i].setIConst(
2750 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2751 break;
2752 case EbtUInt:
2753 resultArray[i].setUConst(
2754 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2755 break;
2756 default:
2757 UNREACHABLE();
2758 break;
Arun Patole274f0702015-05-05 13:33:30 +05302759 }
2760 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002761 break;
Arun Patole274f0702015-05-05 13:33:30 +05302762 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002763
2764 case EOpStep:
2765 {
2766 ASSERT(basicType == EbtFloat);
2767 resultArray = new TConstantUnion[maxObjectSize];
2768 for (size_t i = 0; i < maxObjectSize; i++)
2769 resultArray[i].setFConst(
2770 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2771 break;
2772 }
2773
2774 case EOpLessThanComponentWise:
2775 {
2776 resultArray = new TConstantUnion[maxObjectSize];
2777 for (size_t i = 0; i < maxObjectSize; i++)
2778 {
2779 switch (basicType)
2780 {
2781 case EbtFloat:
2782 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2783 unionArrays[1][i].getFConst());
2784 break;
2785 case EbtInt:
2786 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2787 unionArrays[1][i].getIConst());
2788 break;
2789 case EbtUInt:
2790 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2791 unionArrays[1][i].getUConst());
2792 break;
2793 default:
2794 UNREACHABLE();
2795 break;
2796 }
2797 }
2798 break;
2799 }
2800
2801 case EOpLessThanEqualComponentWise:
2802 {
2803 resultArray = new TConstantUnion[maxObjectSize];
2804 for (size_t i = 0; i < maxObjectSize; i++)
2805 {
2806 switch (basicType)
2807 {
2808 case EbtFloat:
2809 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2810 unionArrays[1][i].getFConst());
2811 break;
2812 case EbtInt:
2813 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2814 unionArrays[1][i].getIConst());
2815 break;
2816 case EbtUInt:
2817 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2818 unionArrays[1][i].getUConst());
2819 break;
2820 default:
2821 UNREACHABLE();
2822 break;
2823 }
2824 }
2825 break;
2826 }
2827
2828 case EOpGreaterThanComponentWise:
2829 {
2830 resultArray = new TConstantUnion[maxObjectSize];
2831 for (size_t i = 0; i < maxObjectSize; i++)
2832 {
2833 switch (basicType)
2834 {
2835 case EbtFloat:
2836 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2837 unionArrays[1][i].getFConst());
2838 break;
2839 case EbtInt:
2840 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2841 unionArrays[1][i].getIConst());
2842 break;
2843 case EbtUInt:
2844 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2845 unionArrays[1][i].getUConst());
2846 break;
2847 default:
2848 UNREACHABLE();
2849 break;
2850 }
2851 }
2852 break;
2853 }
2854 case EOpGreaterThanEqualComponentWise:
2855 {
2856 resultArray = new TConstantUnion[maxObjectSize];
2857 for (size_t i = 0; i < maxObjectSize; i++)
2858 {
2859 switch (basicType)
2860 {
2861 case EbtFloat:
2862 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2863 unionArrays[1][i].getFConst());
2864 break;
2865 case EbtInt:
2866 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2867 unionArrays[1][i].getIConst());
2868 break;
2869 case EbtUInt:
2870 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2871 unionArrays[1][i].getUConst());
2872 break;
2873 default:
2874 UNREACHABLE();
2875 break;
2876 }
2877 }
2878 }
2879 break;
2880
2881 case EOpEqualComponentWise:
2882 {
2883 resultArray = new TConstantUnion[maxObjectSize];
2884 for (size_t i = 0; i < maxObjectSize; i++)
2885 {
2886 switch (basicType)
2887 {
2888 case EbtFloat:
2889 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2890 unionArrays[1][i].getFConst());
2891 break;
2892 case EbtInt:
2893 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2894 unionArrays[1][i].getIConst());
2895 break;
2896 case EbtUInt:
2897 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2898 unionArrays[1][i].getUConst());
2899 break;
2900 case EbtBool:
2901 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2902 unionArrays[1][i].getBConst());
2903 break;
2904 default:
2905 UNREACHABLE();
2906 break;
2907 }
2908 }
2909 break;
2910 }
2911
2912 case EOpNotEqualComponentWise:
2913 {
2914 resultArray = new TConstantUnion[maxObjectSize];
2915 for (size_t i = 0; i < maxObjectSize; i++)
2916 {
2917 switch (basicType)
2918 {
2919 case EbtFloat:
2920 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2921 unionArrays[1][i].getFConst());
2922 break;
2923 case EbtInt:
2924 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2925 unionArrays[1][i].getIConst());
2926 break;
2927 case EbtUInt:
2928 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2929 unionArrays[1][i].getUConst());
2930 break;
2931 case EbtBool:
2932 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2933 unionArrays[1][i].getBConst());
2934 break;
2935 default:
2936 UNREACHABLE();
2937 break;
2938 }
2939 }
2940 break;
2941 }
2942
2943 case EOpDistance:
2944 {
2945 ASSERT(basicType == EbtFloat);
2946 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2947 resultArray = new TConstantUnion();
2948 for (size_t i = 0; i < maxObjectSize; i++)
2949 {
2950 float x = unionArrays[0][i].getFConst();
2951 float y = unionArrays[1][i].getFConst();
2952 distanceArray[i].setFConst(x - y);
2953 }
2954 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2955 break;
2956 }
2957
2958 case EOpDot:
2959 ASSERT(basicType == EbtFloat);
2960 resultArray = new TConstantUnion();
2961 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2962 break;
2963
2964 case EOpCross:
2965 {
2966 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2967 resultArray = new TConstantUnion[maxObjectSize];
2968 float x0 = unionArrays[0][0].getFConst();
2969 float x1 = unionArrays[0][1].getFConst();
2970 float x2 = unionArrays[0][2].getFConst();
2971 float y0 = unionArrays[1][0].getFConst();
2972 float y1 = unionArrays[1][1].getFConst();
2973 float y2 = unionArrays[1][2].getFConst();
2974 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2975 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2976 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2977 break;
2978 }
2979
2980 case EOpReflect:
2981 {
2982 ASSERT(basicType == EbtFloat);
2983 // genType reflect (genType I, genType N) :
2984 // For the incident vector I and surface orientation N, returns the reflection
2985 // direction:
2986 // I - 2 * dot(N, I) * N.
2987 resultArray = new TConstantUnion[maxObjectSize];
2988 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2989 for (size_t i = 0; i < maxObjectSize; i++)
2990 {
2991 float result = unionArrays[0][i].getFConst() -
2992 2.0f * dotProduct * unionArrays[1][i].getFConst();
2993 resultArray[i].setFConst(result);
2994 }
2995 break;
2996 }
2997
2998 case EOpMulMatrixComponentWise:
2999 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003000 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3001 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003002 // Perform component-wise matrix multiplication.
3003 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003004 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003005 angle::Matrix<float> result =
3006 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3007 SetUnionArrayFromMatrix(result, resultArray);
3008 break;
3009 }
3010
3011 case EOpOuterProduct:
3012 {
3013 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003014 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3015 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003016 resultArray = new TConstantUnion[numRows * numCols];
3017 angle::Matrix<float> result =
3018 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3019 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3020 SetUnionArrayFromMatrix(result, resultArray);
3021 break;
3022 }
3023
3024 case EOpClamp:
3025 {
3026 resultArray = new TConstantUnion[maxObjectSize];
3027 for (size_t i = 0; i < maxObjectSize; i++)
3028 {
3029 switch (basicType)
3030 {
3031 case EbtFloat:
3032 {
3033 float x = unionArrays[0][i].getFConst();
3034 float min = unionArrays[1][i].getFConst();
3035 float max = unionArrays[2][i].getFConst();
3036 // Results are undefined if min > max.
3037 if (min > max)
3038 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3039 &resultArray[i]);
3040 else
3041 resultArray[i].setFConst(gl::clamp(x, min, max));
3042 break;
3043 }
3044
3045 case EbtInt:
3046 {
3047 int x = unionArrays[0][i].getIConst();
3048 int min = unionArrays[1][i].getIConst();
3049 int max = unionArrays[2][i].getIConst();
3050 // Results are undefined if min > max.
3051 if (min > max)
3052 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3053 &resultArray[i]);
3054 else
3055 resultArray[i].setIConst(gl::clamp(x, min, max));
3056 break;
3057 }
3058 case EbtUInt:
3059 {
3060 unsigned int x = unionArrays[0][i].getUConst();
3061 unsigned int min = unionArrays[1][i].getUConst();
3062 unsigned int max = unionArrays[2][i].getUConst();
3063 // Results are undefined if min > max.
3064 if (min > max)
3065 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3066 &resultArray[i]);
3067 else
3068 resultArray[i].setUConst(gl::clamp(x, min, max));
3069 break;
3070 }
3071 default:
3072 UNREACHABLE();
3073 break;
3074 }
3075 }
3076 break;
3077 }
3078
3079 case EOpMix:
3080 {
3081 ASSERT(basicType == EbtFloat);
3082 resultArray = new TConstantUnion[maxObjectSize];
3083 for (size_t i = 0; i < maxObjectSize; i++)
3084 {
3085 float x = unionArrays[0][i].getFConst();
3086 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003087 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003088 if (type == EbtFloat)
3089 {
3090 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3091 float a = unionArrays[2][i].getFConst();
3092 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3093 }
3094 else // 3rd parameter is EbtBool
3095 {
3096 ASSERT(type == EbtBool);
3097 // Selects which vector each returned component comes from.
3098 // For a component of a that is false, the corresponding component of x is
3099 // returned.
3100 // For a component of a that is true, the corresponding component of y is
3101 // returned.
3102 bool a = unionArrays[2][i].getBConst();
3103 resultArray[i].setFConst(a ? y : x);
3104 }
3105 }
3106 break;
3107 }
3108
3109 case EOpSmoothStep:
3110 {
3111 ASSERT(basicType == EbtFloat);
3112 resultArray = new TConstantUnion[maxObjectSize];
3113 for (size_t i = 0; i < maxObjectSize; i++)
3114 {
3115 float edge0 = unionArrays[0][i].getFConst();
3116 float edge1 = unionArrays[1][i].getFConst();
3117 float x = unionArrays[2][i].getFConst();
3118 // Results are undefined if edge0 >= edge1.
3119 if (edge0 >= edge1)
3120 {
3121 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3122 }
3123 else
3124 {
3125 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3126 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3127 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3128 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3129 }
3130 }
3131 break;
3132 }
3133
Olli Etuaho74da73f2017-02-01 15:37:48 +00003134 case EOpLdexp:
3135 {
3136 resultArray = new TConstantUnion[maxObjectSize];
3137 for (size_t i = 0; i < maxObjectSize; i++)
3138 {
3139 float x = unionArrays[0][i].getFConst();
3140 int exp = unionArrays[1][i].getIConst();
3141 if (exp > 128)
3142 {
3143 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3144 }
3145 else
3146 {
3147 resultArray[i].setFConst(gl::Ldexp(x, exp));
3148 }
3149 }
3150 break;
3151 }
3152
Jamie Madille72595b2017-06-06 15:12:26 -04003153 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003154 {
3155 ASSERT(basicType == EbtFloat);
3156 // genType faceforward(genType N, genType I, genType Nref) :
3157 // If dot(Nref, I) < 0 return N, otherwise return -N.
3158 resultArray = new TConstantUnion[maxObjectSize];
3159 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3160 for (size_t i = 0; i < maxObjectSize; i++)
3161 {
3162 if (dotProduct < 0)
3163 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3164 else
3165 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3166 }
3167 break;
3168 }
3169
3170 case EOpRefract:
3171 {
3172 ASSERT(basicType == EbtFloat);
3173 // genType refract(genType I, genType N, float eta) :
3174 // For the incident vector I and surface normal N, and the ratio of indices of
3175 // refraction eta,
3176 // return the refraction vector. The result is computed by
3177 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3178 // if (k < 0.0)
3179 // return genType(0.0)
3180 // else
3181 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3182 resultArray = new TConstantUnion[maxObjectSize];
3183 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3184 for (size_t i = 0; i < maxObjectSize; i++)
3185 {
3186 float eta = unionArrays[2][i].getFConst();
3187 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3188 if (k < 0.0f)
3189 resultArray[i].setFConst(0.0f);
3190 else
3191 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3192 (eta * dotProduct + sqrtf(k)) *
3193 unionArrays[1][i].getFConst());
3194 }
3195 break;
3196 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003197 case EOpBitfieldExtract:
3198 {
3199 resultArray = new TConstantUnion[maxObjectSize];
3200 for (size_t i = 0; i < maxObjectSize; ++i)
3201 {
3202 int offset = unionArrays[1][0].getIConst();
3203 int bits = unionArrays[2][0].getIConst();
3204 if (bits == 0)
3205 {
3206 if (aggregate->getBasicType() == EbtInt)
3207 {
3208 resultArray[i].setIConst(0);
3209 }
3210 else
3211 {
3212 ASSERT(aggregate->getBasicType() == EbtUInt);
3213 resultArray[i].setUConst(0);
3214 }
3215 }
3216 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3217 {
3218 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3219 &resultArray[i]);
3220 }
3221 else
3222 {
3223 // bits can be 32 here, so we need to avoid bit shift overflow.
3224 uint32_t maskMsb = 1u << (bits - 1);
3225 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3226 if (aggregate->getBasicType() == EbtInt)
3227 {
3228 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3229 uint32_t resultUnsigned = (value & mask) >> offset;
3230 if ((resultUnsigned & maskMsb) != 0)
3231 {
3232 // The most significant bits (from bits+1 to the most significant bit)
3233 // should be set to 1.
3234 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3235 resultUnsigned |= higherBitsMask;
3236 }
3237 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3238 }
3239 else
3240 {
3241 ASSERT(aggregate->getBasicType() == EbtUInt);
3242 uint32_t value = unionArrays[0][i].getUConst();
3243 resultArray[i].setUConst((value & mask) >> offset);
3244 }
3245 }
3246 }
3247 break;
3248 }
3249 case EOpBitfieldInsert:
3250 {
3251 resultArray = new TConstantUnion[maxObjectSize];
3252 for (size_t i = 0; i < maxObjectSize; ++i)
3253 {
3254 int offset = unionArrays[2][0].getIConst();
3255 int bits = unionArrays[3][0].getIConst();
3256 if (bits == 0)
3257 {
3258 if (aggregate->getBasicType() == EbtInt)
3259 {
3260 int32_t base = unionArrays[0][i].getIConst();
3261 resultArray[i].setIConst(base);
3262 }
3263 else
3264 {
3265 ASSERT(aggregate->getBasicType() == EbtUInt);
3266 uint32_t base = unionArrays[0][i].getUConst();
3267 resultArray[i].setUConst(base);
3268 }
3269 }
3270 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3271 {
3272 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3273 &resultArray[i]);
3274 }
3275 else
3276 {
3277 // bits can be 32 here, so we need to avoid bit shift overflow.
3278 uint32_t maskMsb = 1u << (bits - 1);
3279 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3280 uint32_t baseMask = ~insertMask;
3281 if (aggregate->getBasicType() == EbtInt)
3282 {
3283 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3284 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3285 uint32_t resultUnsigned =
3286 (base & baseMask) | ((insert << offset) & insertMask);
3287 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3288 }
3289 else
3290 {
3291 ASSERT(aggregate->getBasicType() == EbtUInt);
3292 uint32_t base = unionArrays[0][i].getUConst();
3293 uint32_t insert = unionArrays[1][i].getUConst();
3294 resultArray[i].setUConst((base & baseMask) |
3295 ((insert << offset) & insertMask));
3296 }
3297 }
3298 }
3299 break;
3300 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003301
3302 default:
3303 UNREACHABLE();
3304 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303305 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003306 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303307}
3308
3309// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04003310TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
3311{
Yunchao He4f285442017-04-21 12:15:49 +08003312 if (hashFunction == nullptr || name.empty())
Jamie Madillb1a85f42014-08-19 15:23:24 -04003313 return name;
3314 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
3315 TStringStream stream;
3316 stream << HASHED_NAME_PREFIX << std::hex << number;
3317 TString hashedName = stream.str();
3318 return hashedName;
3319}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003320
Olli Etuaho9676d1a2017-05-16 11:29:24 +03003321bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
3322 const NodeInsertMultipleEntry &b)
3323{
3324 if (a.parent != b.parent)
3325 {
3326 return a.parent > b.parent;
3327 }
3328 return a.position > b.position;
3329}
3330
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003331void TIntermTraverser::updateTree()
3332{
Olli Etuaho9676d1a2017-05-16 11:29:24 +03003333 // Sort the insertions so that insertion position is decreasing. This way multiple insertions to
3334 // the same parent node are handled correctly.
3335 std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
Olli Etuahoa6f22092015-05-08 18:31:10 +03003336 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
3337 {
Olli Etuaho9676d1a2017-05-16 11:29:24 +03003338 // We can't know here what the intended ordering of two insertions to the same position is,
3339 // so it is not supported.
3340 ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position ||
3341 mInsertions[ii].parent != mInsertions[ii - 1].parent);
Olli Etuahoa6f22092015-05-08 18:31:10 +03003342 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
3343 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003344 if (!insertion.insertionsAfter.empty())
3345 {
3346 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
3347 insertion.insertionsAfter);
3348 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003349 }
3350 if (!insertion.insertionsBefore.empty())
3351 {
3352 bool inserted =
3353 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
3354 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003355 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03003356 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003357 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
3358 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003359 const NodeUpdateEntry &replacement = mReplacements[ii];
3360 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003361 bool replaced =
3362 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003363 ASSERT(replaced);
3364
Olli Etuahocd94ef92015-04-16 19:18:10 +03003365 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003366 {
3367 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03003368 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003369 // be replaced, we need to make sure we don't update the replaced
3370 // node; instead, we update the replacement node.
3371 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
3372 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003373 NodeUpdateEntry &replacement2 = mReplacements[jj];
3374 if (replacement2.parent == replacement.original)
3375 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003376 }
3377 }
3378 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003379 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
3380 {
3381 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
3382 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003383 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
3384 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003385 ASSERT(replaced);
3386 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03003387
Jamie Madill03d863c2016-07-27 18:15:53 -04003388 clearReplacementQueue();
3389}
3390
3391void TIntermTraverser::clearReplacementQueue()
3392{
Olli Etuahod4f303e2015-05-20 17:09:06 +03003393 mReplacements.clear();
3394 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04003395 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003396}
Jamie Madill1048e432016-07-23 18:51:28 -04003397
Jamie Madill03d863c2016-07-27 18:15:53 -04003398void TIntermTraverser::queueReplacement(TIntermNode *original,
3399 TIntermNode *replacement,
3400 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003401{
Jamie Madill03d863c2016-07-27 18:15:53 -04003402 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04003403}
3404
Jamie Madill03d863c2016-07-27 18:15:53 -04003405void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
3406 TIntermNode *original,
3407 TIntermNode *replacement,
3408 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003409{
Jamie Madill03d863c2016-07-27 18:15:53 -04003410 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
3411 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04003412}
Jamie Madill45bcc782016-11-07 13:58:48 -05003413
Olli Etuahofe486322017-03-21 09:30:54 +00003414TName TIntermTraverser::GetInternalFunctionName(const char *name)
3415{
3416 TString nameStr(name);
Olli Etuahofe486322017-03-21 09:30:54 +00003417 TName nameObj(nameStr);
3418 nameObj.setInternal(true);
3419 return nameObj;
3420}
3421
3422TIntermFunctionPrototype *TIntermTraverser::CreateInternalFunctionPrototypeNode(
3423 const TType &returnType,
3424 const char *name,
3425 const TSymbolUniqueId &functionId)
3426{
3427 TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType, functionId);
3428 functionNode->getFunctionSymbolInfo()->setNameObj(GetInternalFunctionName(name));
3429 return functionNode;
3430}
3431
3432TIntermFunctionDefinition *TIntermTraverser::CreateInternalFunctionDefinitionNode(
3433 const TType &returnType,
3434 const char *name,
3435 TIntermBlock *functionBody,
3436 const TSymbolUniqueId &functionId)
3437{
3438 TIntermFunctionPrototype *prototypeNode =
3439 CreateInternalFunctionPrototypeNode(returnType, name, functionId);
3440 return new TIntermFunctionDefinition(prototypeNode, functionBody);
3441}
3442
3443TIntermAggregate *TIntermTraverser::CreateInternalFunctionCallNode(
3444 const TType &returnType,
3445 const char *name,
3446 const TSymbolUniqueId &functionId,
3447 TIntermSequence *arguments)
3448{
3449 TIntermAggregate *functionNode = TIntermAggregate::CreateFunctionCall(
3450 returnType, functionId, GetInternalFunctionName(name), arguments);
3451 return functionNode;
3452}
3453
Jamie Madill45bcc782016-11-07 13:58:48 -05003454} // namespace sh