blob: 38638f9791c229f8cc6ea70d5e5617bc70bac0a4 [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,
307 TOperator op,
308 TIntermSequence *arguments)
309{
310 TIntermAggregate *constructorNode = new TIntermAggregate(type, op, arguments);
311 ASSERT(constructorNode->isConstructor());
312 return constructorNode;
313}
314
315TIntermAggregate *TIntermAggregate::Create(const TType &type,
316 TOperator op,
317 TIntermSequence *arguments)
318{
319 TIntermAggregate *node = new TIntermAggregate(type, op, arguments);
320 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
321 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
322 ASSERT(!node->isConstructor()); // Should use CreateConstructor
323 return node;
324}
325
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800326TIntermAggregate::TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments)
327 : TIntermOperator(op), mUseEmulatedFunction(false), mGotPrecisionFromChildren(false)
328{
329 if (arguments != nullptr)
330 {
331 mArguments.swap(*arguments);
332 }
333 setTypePrecisionAndQualifier(type);
334}
335
336void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
337{
338 setType(type);
339 mType.setQualifier(EvqTemporary);
340 if (!isFunctionCall())
341 {
342 if (isConstructor())
343 {
344 // Structs should not be precision qualified, the individual members may be.
345 // Built-in types on the other hand should be precision qualified.
346 if (mOp != EOpConstructStruct)
347 {
348 setPrecisionFromChildren();
349 }
350 }
351 else
352 {
353 setPrecisionForBuiltInOp();
354 }
355 if (areChildrenConstQualified())
356 {
357 mType.setQualifier(EvqConst);
358 }
359 }
360}
361
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200362bool TIntermAggregate::areChildrenConstQualified()
363{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800364 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200365 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800366 TIntermTyped *typedArg = arg->getAsTyped();
367 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200368 {
369 return false;
370 }
371 }
372 return true;
373}
374
Olli Etuahod2a67b92014-10-21 16:42:57 +0300375void TIntermAggregate::setPrecisionFromChildren()
376{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300377 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300378 if (getBasicType() == EbtBool)
379 {
380 mType.setPrecision(EbpUndefined);
381 return;
382 }
383
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500384 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800385 TIntermSequence::iterator childIter = mArguments.begin();
386 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300387 {
388 TIntermTyped *typed = (*childIter)->getAsTyped();
389 if (typed)
390 precision = GetHigherPrecision(typed->getPrecision(), precision);
391 ++childIter;
392 }
393 mType.setPrecision(precision);
394}
395
Olli Etuaho9250cb22017-01-21 10:51:27 +0000396void TIntermAggregate::setPrecisionForBuiltInOp()
397{
398 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800399 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000400 if (!setPrecisionForSpecialBuiltInOp())
401 {
402 setPrecisionFromChildren();
403 }
404}
405
406bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
407{
408 switch (mOp)
409 {
410 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800411 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
412 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000413 return true;
414 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800415 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
416 mArguments[1]->getAsTyped()->getPrecision()));
417 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000418 return true;
419 case EOpUaddCarry:
420 case EOpUsubBorrow:
421 mType.setPrecision(EbpHigh);
422 return true;
423 default:
424 return false;
425 }
426}
427
Olli Etuahod2a67b92014-10-21 16:42:57 +0300428void TIntermAggregate::setBuiltInFunctionPrecision()
429{
430 // All built-ins returning bool should be handled as ops, not functions.
431 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800432 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300433
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800434 TPrecision precision = EbpUndefined;
435 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300436 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800437 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300438 // ESSL spec section 8: texture functions get their precision from the sampler.
439 if (typed && IsSampler(typed->getBasicType()))
440 {
441 precision = typed->getPrecision();
442 break;
443 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300444 }
445 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
446 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100447 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300448 mType.setPrecision(EbpHigh);
449 else
450 mType.setPrecision(precision);
451}
452
Olli Etuahof2209f72017-04-01 12:45:55 +0300453TString TIntermAggregate::getSymbolTableMangledName() const
454{
455 ASSERT(!isConstructor());
456 switch (mOp)
457 {
458 case EOpCallInternalRawFunction:
459 case EOpCallBuiltInFunction:
460 case EOpCallFunctionInAST:
461 return TFunction::GetMangledNameFromCall(mFunctionInfo.getName(), mArguments);
462 default:
463 TString opString = GetOperatorString(mOp);
464 return TFunction::GetMangledNameFromCall(opString, mArguments);
465 }
466}
467
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100468void TIntermBlock::appendStatement(TIntermNode *statement)
469{
Olli Etuaho13389b62016-10-16 11:48:18 +0100470 // Declaration nodes with no children can appear if all the declarators just added constants to
471 // the symbol table instead of generating code. They're no-ops so they aren't added to blocks.
472 if (statement != nullptr && (statement->getAsDeclarationNode() == nullptr ||
473 !statement->getAsDeclarationNode()->getSequence()->empty()))
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100474 {
475 mStatements.push_back(statement);
476 }
477}
478
Olli Etuaho16c745a2017-01-16 17:02:27 +0000479void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
480{
481 ASSERT(parameter != nullptr);
482 mParameters.push_back(parameter);
483}
484
Olli Etuaho13389b62016-10-16 11:48:18 +0100485void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
486{
487 ASSERT(declarator != nullptr);
488 ASSERT(declarator->getAsSymbolNode() != nullptr ||
489 (declarator->getAsBinaryNode() != nullptr &&
490 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
491 ASSERT(mDeclarators.empty() ||
492 declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType()));
493 mDeclarators.push_back(declarator);
494}
495
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300496bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
497{
498 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
499 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
500 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
501 return false;
502}
503
Olli Etuaho57961272016-09-14 13:57:46 +0300504bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400505{
506 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100507 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
508 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400509 return false;
510}
511
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500512bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200513{
514 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100515 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200516 return false;
517}
518
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500519bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200520{
521 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
522 return false;
523}
524
Olli Etuahod7a25242015-08-18 13:49:45 +0300525TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
526{
527 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
528 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
529 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
530 mLine = node.mLine;
531}
532
Olli Etuahod4f4c112016-04-15 15:11:24 +0300533bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
534{
535 TIntermAggregate *constructor = getAsAggregate();
536 if (!constructor || !constructor->isConstructor())
537 {
538 return false;
539 }
540 for (TIntermNode *&node : *constructor->getSequence())
541 {
542 if (!node->getAsConstantUnion())
543 return false;
544 }
545 return true;
546}
547
Corentin Wallez509e4562016-08-25 14:55:44 -0400548// static
549TIntermTyped *TIntermTyped::CreateIndexNode(int index)
550{
551 TConstantUnion *u = new TConstantUnion[1];
552 u[0].setIConst(index);
553
554 TType type(EbtInt, EbpUndefined, EvqConst, 1);
555 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
556 return node;
557}
558
559// static
560TIntermTyped *TIntermTyped::CreateZero(const TType &type)
561{
562 TType constType(type);
563 constType.setQualifier(EvqConst);
564
565 if (!type.isArray() && type.getBasicType() != EbtStruct)
566 {
Corentin Wallez509e4562016-08-25 14:55:44 -0400567 size_t size = constType.getObjectSize();
568 TConstantUnion *u = new TConstantUnion[size];
569 for (size_t i = 0; i < size; ++i)
570 {
571 switch (type.getBasicType())
572 {
573 case EbtFloat:
574 u[i].setFConst(0.0f);
575 break;
576 case EbtInt:
577 u[i].setIConst(0);
578 break;
579 case EbtUInt:
580 u[i].setUConst(0u);
581 break;
582 case EbtBool:
583 u[i].setBConst(false);
584 break;
585 default:
Corentin Wallez17a5c062017-01-22 15:20:53 -0500586 // CreateZero is called by ParseContext that keeps parsing even when an error
587 // occurs, so it is possible for CreateZero to be called with non-basic types.
588 // This happens only on error condition but CreateZero needs to return a value
589 // with the correct type to continue the typecheck. That's why we handle
590 // non-basic type by setting whatever value, we just need the type to be right.
591 u[i].setIConst(42);
592 break;
Corentin Wallez509e4562016-08-25 14:55:44 -0400593 }
594 }
595
596 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
597 return node;
598 }
599
Olli Etuaho193c0952017-05-02 15:51:47 +0300600 if (type.getBasicType() == EbtVoid)
601 {
602 // Void array. This happens only on error condition, similarly to the case above. We don't
603 // have a constructor operator for void, so this needs special handling. We'll end up with a
604 // value without the array type, but that should not be a problem.
605 constType.clearArrayness();
606 return CreateZero(constType);
607 }
608
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800609 TIntermSequence *arguments = new TIntermSequence();
Corentin Wallez509e4562016-08-25 14:55:44 -0400610
611 if (type.isArray())
612 {
613 TType elementType(type);
614 elementType.clearArrayness();
615
616 size_t arraySize = type.getArraySize();
617 for (size_t i = 0; i < arraySize; ++i)
618 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800619 arguments->push_back(CreateZero(elementType));
Corentin Wallez509e4562016-08-25 14:55:44 -0400620 }
621 }
622 else
623 {
624 ASSERT(type.getBasicType() == EbtStruct);
625
626 TStructure *structure = type.getStruct();
627 for (const auto &field : structure->fields())
628 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800629 arguments->push_back(CreateZero(*field->type()));
Corentin Wallez509e4562016-08-25 14:55:44 -0400630 }
631 }
632
Olli Etuahofe486322017-03-21 09:30:54 +0000633 return TIntermAggregate::CreateConstructor(constType, sh::TypeToConstructorOperator(type),
634 arguments);
Corentin Wallez509e4562016-08-25 14:55:44 -0400635}
636
Corentin Wallez36fd1002016-12-08 11:30:44 -0500637// static
638TIntermTyped *TIntermTyped::CreateBool(bool value)
639{
640 TConstantUnion *u = new TConstantUnion[1];
641 u[0].setBConst(value);
642
643 TType type(EbtBool, EbpUndefined, EvqConst, 1);
644 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
645 return node;
646}
647
Olli Etuahod7a25242015-08-18 13:49:45 +0300648TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
649{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200650 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300651}
652
Olli Etuahobd674552016-10-06 13:28:42 +0100653void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
654{
Olli Etuahoec9232b2017-03-27 17:01:37 +0300655 setName(function.getName());
Olli Etuahofe486322017-03-21 09:30:54 +0000656 setId(TSymbolUniqueId(function));
657}
658
659TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id) : mId(new TSymbolUniqueId(id))
660{
661}
662
663TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
664 : mName(info.mName), mId(nullptr)
665{
666 if (info.mId)
667 {
668 mId = new TSymbolUniqueId(*info.mId);
669 }
670}
671
672TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
673{
674 mName = info.mName;
675 if (info.mId)
676 {
677 mId = new TSymbolUniqueId(*info.mId);
678 }
679 else
680 {
681 mId = nullptr;
682 }
683 return *this;
684}
685
686void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
687{
688 mId = new TSymbolUniqueId(id);
689}
690
691const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
692{
693 ASSERT(mId);
694 return *mId;
Olli Etuahobd674552016-10-06 13:28:42 +0100695}
696
Olli Etuahod7a25242015-08-18 13:49:45 +0300697TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
698 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300699 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100700 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
701 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300702{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800703 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300704 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800705 TIntermTyped *typedArg = arg->getAsTyped();
706 ASSERT(typedArg != nullptr);
707 TIntermTyped *argCopy = typedArg->deepCopy();
708 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300709 }
710}
711
Olli Etuahofe486322017-03-21 09:30:54 +0000712TIntermAggregate *TIntermAggregate::shallowCopy() const
713{
714 TIntermSequence *copySeq = new TIntermSequence();
715 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
716 TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq);
717 *copyNode->getFunctionSymbolInfo() = mFunctionInfo;
718 copyNode->setLine(mLine);
719 return copyNode;
720}
721
Olli Etuahob6fa0432016-09-28 16:28:05 +0100722TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
723{
724 TIntermTyped *operandCopy = node.mOperand->deepCopy();
725 ASSERT(operandCopy != nullptr);
726 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000727 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100728}
729
Olli Etuahod7a25242015-08-18 13:49:45 +0300730TIntermBinary::TIntermBinary(const TIntermBinary &node)
731 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
732{
733 TIntermTyped *leftCopy = node.mLeft->deepCopy();
734 TIntermTyped *rightCopy = node.mRight->deepCopy();
735 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
736 mLeft = leftCopy;
737 mRight = rightCopy;
738}
739
740TIntermUnary::TIntermUnary(const TIntermUnary &node)
741 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
742{
743 TIntermTyped *operandCopy = node.mOperand->deepCopy();
744 ASSERT(operandCopy != nullptr);
745 mOperand = operandCopy;
746}
747
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300748TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300749{
Olli Etuahod7a25242015-08-18 13:49:45 +0300750 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300751 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
752 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300753 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300754 mCondition = conditionCopy;
755 mTrueExpression = trueCopy;
756 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300757}
758
Jamie Madillb1a85f42014-08-19 15:23:24 -0400759bool TIntermOperator::isAssignment() const
760{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300761 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400762}
763
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300764bool TIntermOperator::isMultiplication() const
765{
766 switch (mOp)
767 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500768 case EOpMul:
769 case EOpMatrixTimesMatrix:
770 case EOpMatrixTimesVector:
771 case EOpMatrixTimesScalar:
772 case EOpVectorTimesMatrix:
773 case EOpVectorTimesScalar:
774 return true;
775 default:
776 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300777 }
778}
779
Jamie Madillb1a85f42014-08-19 15:23:24 -0400780//
781// returns true if the operator is for one of the constructors
782//
783bool TIntermOperator::isConstructor() const
784{
785 switch (mOp)
786 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500787 case EOpConstructVec2:
788 case EOpConstructVec3:
789 case EOpConstructVec4:
790 case EOpConstructMat2:
791 case EOpConstructMat2x3:
792 case EOpConstructMat2x4:
793 case EOpConstructMat3x2:
794 case EOpConstructMat3:
795 case EOpConstructMat3x4:
796 case EOpConstructMat4x2:
797 case EOpConstructMat4x3:
798 case EOpConstructMat4:
799 case EOpConstructFloat:
800 case EOpConstructIVec2:
801 case EOpConstructIVec3:
802 case EOpConstructIVec4:
803 case EOpConstructInt:
804 case EOpConstructUVec2:
805 case EOpConstructUVec3:
806 case EOpConstructUVec4:
807 case EOpConstructUInt:
808 case EOpConstructBVec2:
809 case EOpConstructBVec3:
810 case EOpConstructBVec4:
811 case EOpConstructBool:
812 case EOpConstructStruct:
813 return true;
814 default:
815 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400816 }
817}
818
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800819bool TIntermOperator::isFunctionCall() const
820{
821 switch (mOp)
822 {
823 case EOpCallFunctionInAST:
824 case EOpCallBuiltInFunction:
825 case EOpCallInternalRawFunction:
826 return true;
827 default:
828 return false;
829 }
830}
831
Olli Etuaho1dded802016-08-18 18:13:13 +0300832TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
833{
834 if (left.isMatrix())
835 {
836 if (right.isMatrix())
837 {
838 return EOpMatrixTimesMatrix;
839 }
840 else
841 {
842 if (right.isVector())
843 {
844 return EOpMatrixTimesVector;
845 }
846 else
847 {
848 return EOpMatrixTimesScalar;
849 }
850 }
851 }
852 else
853 {
854 if (right.isMatrix())
855 {
856 if (left.isVector())
857 {
858 return EOpVectorTimesMatrix;
859 }
860 else
861 {
862 return EOpMatrixTimesScalar;
863 }
864 }
865 else
866 {
867 // Neither operand is a matrix.
868 if (left.isVector() == right.isVector())
869 {
870 // Leave as component product.
871 return EOpMul;
872 }
873 else
874 {
875 return EOpVectorTimesScalar;
876 }
877 }
878 }
879}
880
881TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
882{
883 if (left.isMatrix())
884 {
885 if (right.isMatrix())
886 {
887 return EOpMatrixTimesMatrixAssign;
888 }
889 else
890 {
891 // right should be scalar, but this may not be validated yet.
892 return EOpMatrixTimesScalarAssign;
893 }
894 }
895 else
896 {
897 if (right.isMatrix())
898 {
899 // Left should be a vector, but this may not be validated yet.
900 return EOpVectorTimesMatrixAssign;
901 }
902 else
903 {
904 // Neither operand is a matrix.
905 if (left.isVector() == right.isVector())
906 {
907 // Leave as component product.
908 return EOpMulAssign;
909 }
910 else
911 {
912 // left should be vector and right should be scalar, but this may not be validated
913 // yet.
914 return EOpVectorTimesScalarAssign;
915 }
916 }
917 }
918}
919
Jamie Madillb1a85f42014-08-19 15:23:24 -0400920//
921// Make sure the type of a unary operator is appropriate for its
922// combination of operation and operand type.
923//
Olli Etuahoa2234302016-08-31 12:05:39 +0300924void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400925{
Olli Etuahoa2234302016-08-31 12:05:39 +0300926 TQualifier resultQualifier = EvqTemporary;
927 if (mOperand->getQualifier() == EvqConst)
928 resultQualifier = EvqConst;
929
930 unsigned char operandPrimarySize =
931 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400932 switch (mOp)
933 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300934 case EOpFloatBitsToInt:
935 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
936 break;
937 case EOpFloatBitsToUint:
938 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
939 break;
940 case EOpIntBitsToFloat:
941 case EOpUintBitsToFloat:
942 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
943 break;
944 case EOpPackSnorm2x16:
945 case EOpPackUnorm2x16:
946 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800947 case EOpPackUnorm4x8:
948 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300949 setType(TType(EbtUInt, EbpHigh, resultQualifier));
950 break;
951 case EOpUnpackSnorm2x16:
952 case EOpUnpackUnorm2x16:
953 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
954 break;
955 case EOpUnpackHalf2x16:
956 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
957 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800958 case EOpUnpackUnorm4x8:
959 case EOpUnpackSnorm4x8:
960 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
961 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300962 case EOpAny:
963 case EOpAll:
964 setType(TType(EbtBool, EbpUndefined, resultQualifier));
965 break;
966 case EOpLength:
967 case EOpDeterminant:
968 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
969 break;
970 case EOpTranspose:
971 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
972 static_cast<unsigned char>(mOperand->getType().getRows()),
973 static_cast<unsigned char>(mOperand->getType().getCols())));
974 break;
975 case EOpIsInf:
976 case EOpIsNan:
977 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
978 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000979 case EOpBitfieldReverse:
980 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
981 break;
982 case EOpBitCount:
983 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
984 break;
985 case EOpFindLSB:
986 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
987 break;
988 case EOpFindMSB:
989 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
990 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300991 default:
992 setType(mOperand->getType());
993 mType.setQualifier(resultQualifier);
994 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400995 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300996}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400997
Olli Etuahob6fa0432016-09-28 16:28:05 +0100998TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
999 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
1000 mOperand(operand),
1001 mSwizzleOffsets(swizzleOffsets)
1002{
1003 ASSERT(mSwizzleOffsets.size() <= 4);
1004 promote();
1005}
1006
Olli Etuahoa2234302016-08-31 12:05:39 +03001007TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
1008 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
1009{
1010 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001011}
1012
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001013TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1014 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
1015{
1016 promote();
1017}
1018
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001019TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1020 : TIntermNode(), mSymbol(symbol)
1021{
1022 ASSERT(symbol);
1023 setLine(line);
1024}
1025
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001026TIntermTernary::TIntermTernary(TIntermTyped *cond,
1027 TIntermTyped *trueExpression,
1028 TIntermTyped *falseExpression)
1029 : TIntermTyped(trueExpression->getType()),
1030 mCondition(cond),
1031 mTrueExpression(trueExpression),
1032 mFalseExpression(falseExpression)
1033{
1034 getTypePointer()->setQualifier(
1035 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1036}
1037
Olli Etuaho81629262017-04-19 11:56:01 +03001038TIntermLoop::TIntermLoop(TLoopType type,
1039 TIntermNode *init,
1040 TIntermTyped *cond,
1041 TIntermTyped *expr,
1042 TIntermBlock *body)
1043 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1044{
1045 // Declaration nodes with no children can appear if all the declarators just added constants to
1046 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1047 if (mInit && mInit->getAsDeclarationNode() &&
1048 mInit->getAsDeclarationNode()->getSequence()->empty())
1049 {
1050 mInit = nullptr;
1051 }
1052}
1053
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001054// static
1055TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1056 TIntermTyped *trueExpression,
1057 TIntermTyped *falseExpression)
1058{
1059 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1060 falseExpression->getQualifier() == EvqConst)
1061 {
1062 return EvqConst;
1063 }
1064 return EvqTemporary;
1065}
1066
Olli Etuahob6fa0432016-09-28 16:28:05 +01001067void TIntermSwizzle::promote()
1068{
1069 TQualifier resultQualifier = EvqTemporary;
1070 if (mOperand->getQualifier() == EvqConst)
1071 resultQualifier = EvqConst;
1072
1073 auto numFields = mSwizzleOffsets.size();
1074 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1075 static_cast<unsigned char>(numFields)));
1076}
1077
1078bool TIntermSwizzle::hasDuplicateOffsets() const
1079{
1080 int offsetCount[4] = {0u, 0u, 0u, 0u};
1081 for (const auto offset : mSwizzleOffsets)
1082 {
1083 offsetCount[offset]++;
1084 if (offsetCount[offset] > 1)
1085 {
1086 return true;
1087 }
1088 }
1089 return false;
1090}
1091
Olli Etuaho09b04a22016-12-15 13:30:26 +00001092bool TIntermSwizzle::offsetsMatch(int offset) const
1093{
1094 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1095}
1096
Olli Etuahob6fa0432016-09-28 16:28:05 +01001097void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1098{
1099 for (const int offset : mSwizzleOffsets)
1100 {
1101 switch (offset)
1102 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001103 case 0:
1104 *out << "x";
1105 break;
1106 case 1:
1107 *out << "y";
1108 break;
1109 case 2:
1110 *out << "z";
1111 break;
1112 case 3:
1113 *out << "w";
1114 break;
1115 default:
1116 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001117 }
1118 }
1119}
1120
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001121TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1122 const TIntermTyped *left,
1123 const TIntermTyped *right)
1124{
1125 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1126 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1127 right->getQualifier() != EvqConst)
1128 {
1129 return EvqTemporary;
1130 }
1131 return EvqConst;
1132}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001133
1134// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001135void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001136{
Olli Etuaho1dded802016-08-18 18:13:13 +03001137 ASSERT(!isMultiplication() ||
1138 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1139
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001140 // Comma is handled as a special case.
1141 if (mOp == EOpComma)
1142 {
1143 setType(mRight->getType());
1144 return;
1145 }
1146
Jamie Madillb1a85f42014-08-19 15:23:24 -04001147 // Base assumption: just make the type the same as the left
1148 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001149 setType(mLeft->getType());
1150
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001151 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001152 // Binary operations results in temporary variables unless both
1153 // operands are const.
1154 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1155 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001156 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001157 getTypePointer()->setQualifier(EvqTemporary);
1158 }
1159
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001160 // Handle indexing ops.
1161 switch (mOp)
1162 {
1163 case EOpIndexDirect:
1164 case EOpIndexIndirect:
1165 if (mLeft->isArray())
1166 {
1167 mType.clearArrayness();
1168 }
1169 else if (mLeft->isMatrix())
1170 {
1171 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1172 static_cast<unsigned char>(mLeft->getRows())));
1173 }
1174 else if (mLeft->isVector())
1175 {
1176 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1177 }
1178 else
1179 {
1180 UNREACHABLE();
1181 }
1182 return;
1183 case EOpIndexDirectStruct:
1184 {
1185 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1186 const int i = mRight->getAsConstantUnion()->getIConst(0);
1187 setType(*fields[i]->type());
1188 getTypePointer()->setQualifier(resultQualifier);
1189 return;
1190 }
1191 case EOpIndexDirectInterfaceBlock:
1192 {
1193 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1194 const int i = mRight->getAsConstantUnion()->getIConst(0);
1195 setType(*fields[i]->type());
1196 getTypePointer()->setQualifier(resultQualifier);
1197 return;
1198 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001199 default:
1200 break;
1201 }
1202
1203 ASSERT(mLeft->isArray() == mRight->isArray());
1204
1205 // The result gets promoted to the highest precision.
1206 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1207 getTypePointer()->setPrecision(higherPrecision);
1208
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001209 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001210
1211 //
1212 // All scalars or structs. Code after this test assumes this case is removed!
1213 //
1214 if (nominalSize == 1)
1215 {
1216 switch (mOp)
1217 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001218 //
1219 // Promote to conditional
1220 //
1221 case EOpEqual:
1222 case EOpNotEqual:
1223 case EOpLessThan:
1224 case EOpGreaterThan:
1225 case EOpLessThanEqual:
1226 case EOpGreaterThanEqual:
1227 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1228 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001229
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001230 //
1231 // And and Or operate on conditionals
1232 //
1233 case EOpLogicalAnd:
1234 case EOpLogicalXor:
1235 case EOpLogicalOr:
1236 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1237 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1238 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001239
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001240 default:
1241 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001242 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001243 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001244 }
1245
1246 // If we reach here, at least one of the operands is vector or matrix.
1247 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001248 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001249
Jamie Madillb1a85f42014-08-19 15:23:24 -04001250 switch (mOp)
1251 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001252 case EOpMul:
1253 break;
1254 case EOpMatrixTimesScalar:
1255 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001256 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001257 setType(TType(basicType, higherPrecision, resultQualifier,
1258 static_cast<unsigned char>(mRight->getCols()),
1259 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001260 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001261 break;
1262 case EOpMatrixTimesVector:
1263 setType(TType(basicType, higherPrecision, resultQualifier,
1264 static_cast<unsigned char>(mLeft->getRows()), 1));
1265 break;
1266 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001267 setType(TType(basicType, higherPrecision, resultQualifier,
1268 static_cast<unsigned char>(mRight->getCols()),
1269 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001270 break;
1271 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001272 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001273 static_cast<unsigned char>(nominalSize), 1));
1274 break;
1275 case EOpVectorTimesMatrix:
1276 setType(TType(basicType, higherPrecision, resultQualifier,
1277 static_cast<unsigned char>(mRight->getCols()), 1));
1278 break;
1279 case EOpMulAssign:
1280 case EOpVectorTimesScalarAssign:
1281 case EOpVectorTimesMatrixAssign:
1282 case EOpMatrixTimesScalarAssign:
1283 case EOpMatrixTimesMatrixAssign:
1284 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1285 break;
1286 case EOpAssign:
1287 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001288 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1289 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1290 break;
1291 case EOpAdd:
1292 case EOpSub:
1293 case EOpDiv:
1294 case EOpIMod:
1295 case EOpBitShiftLeft:
1296 case EOpBitShiftRight:
1297 case EOpBitwiseAnd:
1298 case EOpBitwiseXor:
1299 case EOpBitwiseOr:
1300 case EOpAddAssign:
1301 case EOpSubAssign:
1302 case EOpDivAssign:
1303 case EOpIModAssign:
1304 case EOpBitShiftLeftAssign:
1305 case EOpBitShiftRightAssign:
1306 case EOpBitwiseAndAssign:
1307 case EOpBitwiseXorAssign:
1308 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001309 {
1310 const int secondarySize =
1311 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1312 setType(TType(basicType, higherPrecision, resultQualifier,
1313 static_cast<unsigned char>(nominalSize),
1314 static_cast<unsigned char>(secondarySize)));
1315 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001316 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001317 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001318 case EOpEqual:
1319 case EOpNotEqual:
1320 case EOpLessThan:
1321 case EOpGreaterThan:
1322 case EOpLessThanEqual:
1323 case EOpGreaterThanEqual:
1324 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1325 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001326 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001327 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001328
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001329 case EOpIndexDirect:
1330 case EOpIndexIndirect:
1331 case EOpIndexDirectInterfaceBlock:
1332 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001333 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001334 UNREACHABLE();
1335 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001336 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001337 UNREACHABLE();
1338 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001339 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001340}
1341
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001342const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001343{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001344 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001345 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001346 ASSERT(index < static_cast<int>(getType().getArraySize()));
1347 TType arrayElementType = getType();
1348 arrayElementType.clearArrayness();
1349 size_t arrayElementSize = arrayElementType.getObjectSize();
1350 return &mUnionArrayPointer[arrayElementSize * index];
1351 }
1352 else if (isMatrix())
1353 {
1354 ASSERT(index < getType().getCols());
1355 int size = getType().getRows();
1356 return &mUnionArrayPointer[size * index];
1357 }
1358 else if (isVector())
1359 {
1360 ASSERT(index < getType().getNominalSize());
1361 return &mUnionArrayPointer[index];
1362 }
1363 else
1364 {
1365 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001366 return nullptr;
1367 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001368}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001369
Olli Etuahob6fa0432016-09-28 16:28:05 +01001370TIntermTyped *TIntermSwizzle::fold()
1371{
1372 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1373 if (operandConstant == nullptr)
1374 {
1375 return nullptr;
1376 }
1377
1378 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1379 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1380 {
1381 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1382 }
1383 return CreateFoldedNode(constArray, this, mType.getQualifier());
1384}
1385
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001386TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1387{
1388 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1389 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1390 switch (mOp)
1391 {
1392 case EOpIndexDirect:
1393 {
1394 if (leftConstant == nullptr || rightConstant == nullptr)
1395 {
1396 return nullptr;
1397 }
1398 int index = rightConstant->getIConst(0);
1399
1400 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1401 return CreateFoldedNode(constArray, this, mType.getQualifier());
1402 }
1403 case EOpIndexDirectStruct:
1404 {
1405 if (leftConstant == nullptr || rightConstant == nullptr)
1406 {
1407 return nullptr;
1408 }
1409 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1410 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1411
1412 size_t previousFieldsSize = 0;
1413 for (size_t i = 0; i < index; ++i)
1414 {
1415 previousFieldsSize += fields[i]->type()->getObjectSize();
1416 }
1417
1418 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1419 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1420 }
1421 case EOpIndexIndirect:
1422 case EOpIndexDirectInterfaceBlock:
1423 // Can never be constant folded.
1424 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001425 default:
1426 {
1427 if (leftConstant == nullptr || rightConstant == nullptr)
1428 {
1429 return nullptr;
1430 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001431 TConstantUnion *constArray =
1432 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001433
1434 // Nodes may be constant folded without being qualified as constant.
1435 return CreateFoldedNode(constArray, this, mType.getQualifier());
1436 }
1437 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001438}
1439
Olli Etuahof119a262016-08-19 15:54:22 +03001440TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001441{
1442 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1443 if (operandConstant == nullptr)
1444 {
1445 return nullptr;
1446 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301447
1448 TConstantUnion *constArray = nullptr;
1449 switch (mOp)
1450 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001451 case EOpAny:
1452 case EOpAll:
1453 case EOpLength:
1454 case EOpTranspose:
1455 case EOpDeterminant:
1456 case EOpInverse:
1457 case EOpPackSnorm2x16:
1458 case EOpUnpackSnorm2x16:
1459 case EOpPackUnorm2x16:
1460 case EOpUnpackUnorm2x16:
1461 case EOpPackHalf2x16:
1462 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001463 case EOpPackUnorm4x8:
1464 case EOpPackSnorm4x8:
1465 case EOpUnpackUnorm4x8:
1466 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001467 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1468 break;
1469 default:
1470 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1471 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301472 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001473
1474 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001475 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001476}
1477
Olli Etuahof119a262016-08-19 15:54:22 +03001478TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001479{
1480 // Make sure that all params are constant before actual constant folding.
1481 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001482 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001483 if (param->getAsConstantUnion() == nullptr)
1484 {
1485 return nullptr;
1486 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001487 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001488 TConstantUnion *constArray = nullptr;
1489 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001490 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001491 else
Olli Etuahof119a262016-08-19 15:54:22 +03001492 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001493
1494 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001495 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001496}
1497
Jamie Madillb1a85f42014-08-19 15:23:24 -04001498//
1499// The fold functions see if an operation on a constant can be done in place,
1500// without generating run-time code.
1501//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001502// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001503//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001504TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1505 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001506 TDiagnostics *diagnostics,
1507 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001508{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001509 const TConstantUnion *leftArray = getUnionArrayPointer();
1510 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001511
Olli Etuahof119a262016-08-19 15:54:22 +03001512 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001513
1514 size_t objectSize = getType().getObjectSize();
1515
1516 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1517 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1518 {
1519 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1520 }
1521 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1522 {
1523 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001524 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001525 objectSize = rightNode->getType().getObjectSize();
1526 }
1527
1528 TConstantUnion *resultArray = nullptr;
1529
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001530 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001531 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001532 case EOpAdd:
1533 resultArray = new TConstantUnion[objectSize];
1534 for (size_t i = 0; i < objectSize; i++)
1535 resultArray[i] =
1536 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1537 break;
1538 case EOpSub:
1539 resultArray = new TConstantUnion[objectSize];
1540 for (size_t i = 0; i < objectSize; i++)
1541 resultArray[i] =
1542 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1543 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001544
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001545 case EOpMul:
1546 case EOpVectorTimesScalar:
1547 case EOpMatrixTimesScalar:
1548 resultArray = new TConstantUnion[objectSize];
1549 for (size_t i = 0; i < objectSize; i++)
1550 resultArray[i] =
1551 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1552 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001553
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001554 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001555 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001556 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001557 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001558
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001559 const int leftCols = getCols();
1560 const int leftRows = getRows();
1561 const int rightCols = rightNode->getType().getCols();
1562 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001563 const int resultCols = rightCols;
1564 const int resultRows = leftRows;
1565
1566 resultArray = new TConstantUnion[resultCols * resultRows];
1567 for (int row = 0; row < resultRows; row++)
1568 {
1569 for (int column = 0; column < resultCols; column++)
1570 {
1571 resultArray[resultRows * column + row].setFConst(0.0f);
1572 for (int i = 0; i < leftCols; i++)
1573 {
1574 resultArray[resultRows * column + row].setFConst(
1575 resultArray[resultRows * column + row].getFConst() +
1576 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001577 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001578 }
1579 }
1580 }
1581 }
1582 break;
1583
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001584 case EOpDiv:
1585 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001586 {
1587 resultArray = new TConstantUnion[objectSize];
1588 for (size_t i = 0; i < objectSize; i++)
1589 {
1590 switch (getType().getBasicType())
1591 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001592 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001593 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001594 ASSERT(op == EOpDiv);
1595 float dividend = leftArray[i].getFConst();
1596 float divisor = rightArray[i].getFConst();
1597 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001598 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001599 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001600 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001601 diagnostics->warning(
1602 getLine(),
1603 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001604 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001605 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001606 }
1607 else
1608 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001609 diagnostics->warning(getLine(),
1610 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001611 bool negativeResult =
1612 std::signbit(dividend) != std::signbit(divisor);
1613 resultArray[i].setFConst(
1614 negativeResult ? -std::numeric_limits<float>::infinity()
1615 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001616 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001617 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 else if (gl::isInf(dividend) && gl::isInf(divisor))
1619 {
1620 diagnostics->warning(getLine(),
1621 "Infinity divided by infinity during constant "
1622 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001623 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001624 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1625 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001626 else
1627 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001628 float result = dividend / divisor;
1629 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001630 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001631 diagnostics->warning(
1632 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001633 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001634 }
1635 resultArray[i].setFConst(result);
1636 }
1637 break;
1638 }
1639 case EbtInt:
1640 if (rightArray[i] == 0)
1641 {
1642 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001643 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001644 resultArray[i].setIConst(INT_MAX);
1645 }
1646 else
1647 {
1648 int lhs = leftArray[i].getIConst();
1649 int divisor = rightArray[i].getIConst();
1650 if (op == EOpDiv)
1651 {
1652 // Check for the special case where the minimum representable number
1653 // is
1654 // divided by -1. If left alone this leads to integer overflow in
1655 // C++.
1656 // ESSL 3.00.6 section 4.1.3 Integers:
1657 // "However, for the case where the minimum representable value is
1658 // divided by -1, it is allowed to return either the minimum
1659 // representable value or the maximum representable value."
1660 if (lhs == -0x7fffffff - 1 && divisor == -1)
1661 {
1662 resultArray[i].setIConst(0x7fffffff);
1663 }
1664 else
1665 {
1666 resultArray[i].setIConst(lhs / divisor);
1667 }
Olli Etuahod4453572016-09-27 13:21:46 +01001668 }
1669 else
1670 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001671 ASSERT(op == EOpIMod);
1672 if (lhs < 0 || divisor < 0)
1673 {
1674 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1675 // when
1676 // either one of the operands is negative.
1677 diagnostics->warning(getLine(),
1678 "Negative modulus operator operand "
1679 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001680 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001681 resultArray[i].setIConst(0);
1682 }
1683 else
1684 {
1685 resultArray[i].setIConst(lhs % divisor);
1686 }
Olli Etuahod4453572016-09-27 13:21:46 +01001687 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001688 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001689 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001690
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001691 case EbtUInt:
1692 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001693 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001694 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001695 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001696 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001697 }
1698 else
1699 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001700 if (op == EOpDiv)
1701 {
1702 resultArray[i].setUConst(leftArray[i].getUConst() /
1703 rightArray[i].getUConst());
1704 }
1705 else
1706 {
1707 ASSERT(op == EOpIMod);
1708 resultArray[i].setUConst(leftArray[i].getUConst() %
1709 rightArray[i].getUConst());
1710 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001711 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001712 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001713
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001714 default:
1715 UNREACHABLE();
1716 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001717 }
1718 }
1719 }
1720 break;
1721
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001722 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001723 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001724 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001725 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001726
1727 const int matrixCols = getCols();
1728 const int matrixRows = getRows();
1729
1730 resultArray = new TConstantUnion[matrixRows];
1731
1732 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1733 {
1734 resultArray[matrixRow].setFConst(0.0f);
1735 for (int col = 0; col < matrixCols; col++)
1736 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001737 resultArray[matrixRow].setFConst(
1738 resultArray[matrixRow].getFConst() +
1739 leftArray[col * matrixRows + matrixRow].getFConst() *
1740 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001741 }
1742 }
1743 }
1744 break;
1745
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001746 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001747 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001748 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001749 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001750
1751 const int matrixCols = rightNode->getType().getCols();
1752 const int matrixRows = rightNode->getType().getRows();
1753
1754 resultArray = new TConstantUnion[matrixCols];
1755
1756 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1757 {
1758 resultArray[matrixCol].setFConst(0.0f);
1759 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1760 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001761 resultArray[matrixCol].setFConst(
1762 resultArray[matrixCol].getFConst() +
1763 leftArray[matrixRow].getFConst() *
1764 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001765 }
1766 }
1767 }
1768 break;
1769
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001770 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001771 {
1772 resultArray = new TConstantUnion[objectSize];
1773 for (size_t i = 0; i < objectSize; i++)
1774 {
1775 resultArray[i] = leftArray[i] && rightArray[i];
1776 }
1777 }
1778 break;
1779
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001780 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001781 {
1782 resultArray = new TConstantUnion[objectSize];
1783 for (size_t i = 0; i < objectSize; i++)
1784 {
1785 resultArray[i] = leftArray[i] || rightArray[i];
1786 }
1787 }
1788 break;
1789
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001790 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001791 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001792 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001793 resultArray = new TConstantUnion[objectSize];
1794 for (size_t i = 0; i < objectSize; i++)
1795 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001796 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001797 }
1798 }
1799 break;
1800
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001801 case EOpBitwiseAnd:
1802 resultArray = new TConstantUnion[objectSize];
1803 for (size_t i = 0; i < objectSize; i++)
1804 resultArray[i] = leftArray[i] & rightArray[i];
1805 break;
1806 case EOpBitwiseXor:
1807 resultArray = new TConstantUnion[objectSize];
1808 for (size_t i = 0; i < objectSize; i++)
1809 resultArray[i] = leftArray[i] ^ rightArray[i];
1810 break;
1811 case EOpBitwiseOr:
1812 resultArray = new TConstantUnion[objectSize];
1813 for (size_t i = 0; i < objectSize; i++)
1814 resultArray[i] = leftArray[i] | rightArray[i];
1815 break;
1816 case EOpBitShiftLeft:
1817 resultArray = new TConstantUnion[objectSize];
1818 for (size_t i = 0; i < objectSize; i++)
1819 resultArray[i] =
1820 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1821 break;
1822 case EOpBitShiftRight:
1823 resultArray = new TConstantUnion[objectSize];
1824 for (size_t i = 0; i < objectSize; i++)
1825 resultArray[i] =
1826 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1827 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001828
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001829 case EOpLessThan:
1830 ASSERT(objectSize == 1);
1831 resultArray = new TConstantUnion[1];
1832 resultArray->setBConst(*leftArray < *rightArray);
1833 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001834
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001835 case EOpGreaterThan:
1836 ASSERT(objectSize == 1);
1837 resultArray = new TConstantUnion[1];
1838 resultArray->setBConst(*leftArray > *rightArray);
1839 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001840
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001841 case EOpLessThanEqual:
1842 ASSERT(objectSize == 1);
1843 resultArray = new TConstantUnion[1];
1844 resultArray->setBConst(!(*leftArray > *rightArray));
1845 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001846
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001847 case EOpGreaterThanEqual:
1848 ASSERT(objectSize == 1);
1849 resultArray = new TConstantUnion[1];
1850 resultArray->setBConst(!(*leftArray < *rightArray));
1851 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001852
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001853 case EOpEqual:
1854 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001855 {
1856 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001857 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001858 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001859 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001860 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001861 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001862 equal = false;
1863 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001864 }
1865 }
1866 if (op == EOpEqual)
1867 {
1868 resultArray->setBConst(equal);
1869 }
1870 else
1871 {
1872 resultArray->setBConst(!equal);
1873 }
1874 }
1875 break;
1876
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001877 default:
1878 UNREACHABLE();
1879 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001880 }
1881 return resultArray;
1882}
1883
Olli Etuahof119a262016-08-19 15:54:22 +03001884// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1885// code. Returns the constant value to keep using. Nullptr should not be returned.
1886TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001887{
Olli Etuahof119a262016-08-19 15:54:22 +03001888 // Do operations where the return type may have a different number of components compared to the
1889 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001890
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001891 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001892 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301893
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001894 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301895 TConstantUnion *resultArray = nullptr;
1896 switch (op)
1897 {
Olli Etuahof119a262016-08-19 15:54:22 +03001898 case EOpAny:
1899 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301900 resultArray = new TConstantUnion();
1901 resultArray->setBConst(false);
1902 for (size_t i = 0; i < objectSize; i++)
1903 {
1904 if (operandArray[i].getBConst())
1905 {
1906 resultArray->setBConst(true);
1907 break;
1908 }
1909 }
1910 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301911
Olli Etuahof119a262016-08-19 15:54:22 +03001912 case EOpAll:
1913 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301914 resultArray = new TConstantUnion();
1915 resultArray->setBConst(true);
1916 for (size_t i = 0; i < objectSize; i++)
1917 {
1918 if (!operandArray[i].getBConst())
1919 {
1920 resultArray->setBConst(false);
1921 break;
1922 }
1923 }
1924 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301925
Olli Etuahof119a262016-08-19 15:54:22 +03001926 case EOpLength:
1927 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301928 resultArray = new TConstantUnion();
1929 resultArray->setFConst(VectorLength(operandArray, objectSize));
1930 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301931
Olli Etuahof119a262016-08-19 15:54:22 +03001932 case EOpTranspose:
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 resultArray = new TConstantUnion[objectSize];
1936 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001937 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301938 SetUnionArrayFromMatrix(result, resultArray);
1939 break;
1940 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301941
Olli Etuahof119a262016-08-19 15:54:22 +03001942 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301943 {
Olli Etuahof119a262016-08-19 15:54:22 +03001944 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945 unsigned int size = getType().getNominalSize();
1946 ASSERT(size >= 2 && size <= 4);
1947 resultArray = new TConstantUnion();
1948 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1949 break;
1950 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301951
Olli Etuahof119a262016-08-19 15:54:22 +03001952 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301953 {
Olli Etuahof119a262016-08-19 15:54:22 +03001954 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301955 unsigned int size = getType().getNominalSize();
1956 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001957 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301958 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1959 SetUnionArrayFromMatrix(result, resultArray);
1960 break;
1961 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301962
Olli Etuahof119a262016-08-19 15:54:22 +03001963 case EOpPackSnorm2x16:
1964 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301965 ASSERT(getType().getNominalSize() == 2);
1966 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001967 resultArray->setUConst(
1968 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301969 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301970
Olli Etuahof119a262016-08-19 15:54:22 +03001971 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301972 {
Olli Etuahof119a262016-08-19 15:54:22 +03001973 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301974 resultArray = new TConstantUnion[2];
1975 float f1, f2;
1976 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1977 resultArray[0].setFConst(f1);
1978 resultArray[1].setFConst(f2);
1979 break;
1980 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301981
Olli Etuahof119a262016-08-19 15:54:22 +03001982 case EOpPackUnorm2x16:
1983 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301984 ASSERT(getType().getNominalSize() == 2);
1985 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001986 resultArray->setUConst(
1987 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301988 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301989
Olli Etuahof119a262016-08-19 15:54:22 +03001990 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301991 {
Olli Etuahof119a262016-08-19 15:54:22 +03001992 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301993 resultArray = new TConstantUnion[2];
1994 float f1, f2;
1995 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1996 resultArray[0].setFConst(f1);
1997 resultArray[1].setFConst(f2);
1998 break;
1999 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302000
Olli Etuahof119a262016-08-19 15:54:22 +03002001 case EOpPackHalf2x16:
2002 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302003 ASSERT(getType().getNominalSize() == 2);
2004 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002005 resultArray->setUConst(
2006 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302007 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302008
Olli Etuahof119a262016-08-19 15:54:22 +03002009 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302010 {
Olli Etuahof119a262016-08-19 15:54:22 +03002011 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302012 resultArray = new TConstantUnion[2];
2013 float f1, f2;
2014 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2015 resultArray[0].setFConst(f1);
2016 resultArray[1].setFConst(f2);
2017 break;
2018 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302019
Olli Etuaho25aef452017-01-29 16:15:44 -08002020 case EOpPackUnorm4x8:
2021 {
2022 ASSERT(getType().getBasicType() == EbtFloat);
2023 resultArray = new TConstantUnion();
2024 resultArray->setUConst(
2025 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2026 operandArray[2].getFConst(), operandArray[3].getFConst()));
2027 break;
2028 }
2029 case EOpPackSnorm4x8:
2030 {
2031 ASSERT(getType().getBasicType() == EbtFloat);
2032 resultArray = new TConstantUnion();
2033 resultArray->setUConst(
2034 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2035 operandArray[2].getFConst(), operandArray[3].getFConst()));
2036 break;
2037 }
2038 case EOpUnpackUnorm4x8:
2039 {
2040 ASSERT(getType().getBasicType() == EbtUInt);
2041 resultArray = new TConstantUnion[4];
2042 float f[4];
2043 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2044 for (size_t i = 0; i < 4; ++i)
2045 {
2046 resultArray[i].setFConst(f[i]);
2047 }
2048 break;
2049 }
2050 case EOpUnpackSnorm4x8:
2051 {
2052 ASSERT(getType().getBasicType() == EbtUInt);
2053 resultArray = new TConstantUnion[4];
2054 float f[4];
2055 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2056 for (size_t i = 0; i < 4; ++i)
2057 {
2058 resultArray[i].setFConst(f[i]);
2059 }
2060 break;
2061 }
2062
Olli Etuahof119a262016-08-19 15:54:22 +03002063 default:
2064 UNREACHABLE();
2065 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302066 }
2067
2068 return resultArray;
2069}
2070
Olli Etuahof119a262016-08-19 15:54:22 +03002071TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2072 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302073{
Olli Etuahof119a262016-08-19 15:54:22 +03002074 // Do unary operations where each component of the result is computed based on the corresponding
2075 // component of the operand. Also folds normalize, though the divisor in that case takes all
2076 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302077
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002078 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002079 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002080
2081 size_t objectSize = getType().getObjectSize();
2082
Arun Patoleab2b9a22015-07-06 18:27:56 +05302083 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2084 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302085 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002086 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302087 {
Olli Etuahof119a262016-08-19 15:54:22 +03002088 case EOpNegative:
2089 switch (getType().getBasicType())
2090 {
2091 case EbtFloat:
2092 resultArray[i].setFConst(-operandArray[i].getFConst());
2093 break;
2094 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002095 if (operandArray[i] == std::numeric_limits<int>::min())
2096 {
2097 // The minimum representable integer doesn't have a positive
2098 // counterpart, rather the negation overflows and in ESSL is supposed to
2099 // wrap back to the minimum representable integer. Make sure that we
2100 // don't actually let the negation overflow, which has undefined
2101 // behavior in C++.
2102 resultArray[i].setIConst(std::numeric_limits<int>::min());
2103 }
2104 else
2105 {
2106 resultArray[i].setIConst(-operandArray[i].getIConst());
2107 }
Olli Etuahof119a262016-08-19 15:54:22 +03002108 break;
2109 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002110 if (operandArray[i] == 0x80000000u)
2111 {
2112 resultArray[i].setUConst(0x80000000u);
2113 }
2114 else
2115 {
2116 resultArray[i].setUConst(static_cast<unsigned int>(
2117 -static_cast<int>(operandArray[i].getUConst())));
2118 }
Olli Etuahof119a262016-08-19 15:54:22 +03002119 break;
2120 default:
2121 UNREACHABLE();
2122 return nullptr;
2123 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302124 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302125
Olli Etuahof119a262016-08-19 15:54:22 +03002126 case EOpPositive:
2127 switch (getType().getBasicType())
2128 {
2129 case EbtFloat:
2130 resultArray[i].setFConst(operandArray[i].getFConst());
2131 break;
2132 case EbtInt:
2133 resultArray[i].setIConst(operandArray[i].getIConst());
2134 break;
2135 case EbtUInt:
2136 resultArray[i].setUConst(static_cast<unsigned int>(
2137 static_cast<int>(operandArray[i].getUConst())));
2138 break;
2139 default:
2140 UNREACHABLE();
2141 return nullptr;
2142 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302143 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302144
Olli Etuahof119a262016-08-19 15:54:22 +03002145 case EOpLogicalNot:
2146 switch (getType().getBasicType())
2147 {
2148 case EbtBool:
2149 resultArray[i].setBConst(!operandArray[i].getBConst());
2150 break;
2151 default:
2152 UNREACHABLE();
2153 return nullptr;
2154 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302155 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302156
Olli Etuahof119a262016-08-19 15:54:22 +03002157 case EOpBitwiseNot:
2158 switch (getType().getBasicType())
2159 {
2160 case EbtInt:
2161 resultArray[i].setIConst(~operandArray[i].getIConst());
2162 break;
2163 case EbtUInt:
2164 resultArray[i].setUConst(~operandArray[i].getUConst());
2165 break;
2166 default:
2167 UNREACHABLE();
2168 return nullptr;
2169 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302170 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302171
Olli Etuahof119a262016-08-19 15:54:22 +03002172 case EOpRadians:
2173 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302174 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2175 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302176
Olli Etuahof119a262016-08-19 15:54:22 +03002177 case EOpDegrees:
2178 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302179 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2180 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302181
Olli Etuahof119a262016-08-19 15:54:22 +03002182 case EOpSin:
2183 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302184 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302185
Olli Etuahof119a262016-08-19 15:54:22 +03002186 case EOpCos:
2187 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2188 break;
2189
2190 case EOpTan:
2191 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2192 break;
2193
2194 case EOpAsin:
2195 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2196 // 0.
2197 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2198 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2199 diagnostics, &resultArray[i]);
2200 else
2201 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2202 break;
2203
2204 case EOpAcos:
2205 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2206 // 0.
2207 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2208 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2209 diagnostics, &resultArray[i]);
2210 else
2211 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2212 break;
2213
2214 case EOpAtan:
2215 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2216 break;
2217
2218 case EOpSinh:
2219 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2220 break;
2221
2222 case EOpCosh:
2223 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2224 break;
2225
2226 case EOpTanh:
2227 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2228 break;
2229
2230 case EOpAsinh:
2231 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2232 break;
2233
2234 case EOpAcosh:
2235 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2236 if (operandArray[i].getFConst() < 1.0f)
2237 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2238 diagnostics, &resultArray[i]);
2239 else
2240 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2241 break;
2242
2243 case EOpAtanh:
2244 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2245 // 0.
2246 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2247 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2248 diagnostics, &resultArray[i]);
2249 else
2250 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2251 break;
2252
2253 case EOpAbs:
2254 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302255 {
Olli Etuahof119a262016-08-19 15:54:22 +03002256 case EbtFloat:
2257 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2258 break;
2259 case EbtInt:
2260 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2261 break;
2262 default:
2263 UNREACHABLE();
2264 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302265 }
2266 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002267
2268 case EOpSign:
2269 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302270 {
Olli Etuahof119a262016-08-19 15:54:22 +03002271 case EbtFloat:
2272 {
2273 float fConst = operandArray[i].getFConst();
2274 float fResult = 0.0f;
2275 if (fConst > 0.0f)
2276 fResult = 1.0f;
2277 else if (fConst < 0.0f)
2278 fResult = -1.0f;
2279 resultArray[i].setFConst(fResult);
2280 break;
2281 }
2282 case EbtInt:
2283 {
2284 int iConst = operandArray[i].getIConst();
2285 int iResult = 0;
2286 if (iConst > 0)
2287 iResult = 1;
2288 else if (iConst < 0)
2289 iResult = -1;
2290 resultArray[i].setIConst(iResult);
2291 break;
2292 }
2293 default:
2294 UNREACHABLE();
2295 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302296 }
2297 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302298
Olli Etuahof119a262016-08-19 15:54:22 +03002299 case EOpFloor:
2300 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2301 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302302
Olli Etuahof119a262016-08-19 15:54:22 +03002303 case EOpTrunc:
2304 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2305 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302306
Olli Etuahof119a262016-08-19 15:54:22 +03002307 case EOpRound:
2308 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2309 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302310
Olli Etuahof119a262016-08-19 15:54:22 +03002311 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302312 {
Olli Etuahof119a262016-08-19 15:54:22 +03002313 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302314 float x = operandArray[i].getFConst();
2315 float result;
2316 float fractPart = modff(x, &result);
2317 if (fabsf(fractPart) == 0.5f)
2318 result = 2.0f * roundf(x / 2.0f);
2319 else
2320 result = roundf(x);
2321 resultArray[i].setFConst(result);
2322 break;
2323 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302324
Olli Etuahof119a262016-08-19 15:54:22 +03002325 case EOpCeil:
2326 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2327 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302328
Olli Etuahof119a262016-08-19 15:54:22 +03002329 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302330 {
Olli Etuahof119a262016-08-19 15:54:22 +03002331 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302332 float x = operandArray[i].getFConst();
2333 resultArray[i].setFConst(x - floorf(x));
2334 break;
2335 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302336
Olli Etuahof119a262016-08-19 15:54:22 +03002337 case EOpIsNan:
2338 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302339 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2340 break;
Arun Patole551279e2015-07-07 18:18:23 +05302341
Olli Etuahof119a262016-08-19 15:54:22 +03002342 case EOpIsInf:
2343 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302344 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2345 break;
Arun Patole551279e2015-07-07 18:18:23 +05302346
Olli Etuahof119a262016-08-19 15:54:22 +03002347 case EOpFloatBitsToInt:
2348 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302349 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2350 break;
Arun Patole551279e2015-07-07 18:18:23 +05302351
Olli Etuahof119a262016-08-19 15:54:22 +03002352 case EOpFloatBitsToUint:
2353 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302354 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2355 break;
Arun Patole551279e2015-07-07 18:18:23 +05302356
Olli Etuahof119a262016-08-19 15:54:22 +03002357 case EOpIntBitsToFloat:
2358 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302359 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2360 break;
Arun Patole551279e2015-07-07 18:18:23 +05302361
Olli Etuahof119a262016-08-19 15:54:22 +03002362 case EOpUintBitsToFloat:
2363 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302364 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2365 break;
Arun Patole551279e2015-07-07 18:18:23 +05302366
Olli Etuahof119a262016-08-19 15:54:22 +03002367 case EOpExp:
2368 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2369 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302370
Olli Etuahof119a262016-08-19 15:54:22 +03002371 case EOpLog:
2372 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2373 if (operandArray[i].getFConst() <= 0.0f)
2374 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2375 diagnostics, &resultArray[i]);
2376 else
2377 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2378 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302379
Olli Etuahof119a262016-08-19 15:54:22 +03002380 case EOpExp2:
2381 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2382 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302383
Olli Etuahof119a262016-08-19 15:54:22 +03002384 case EOpLog2:
2385 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2386 // And log2f is not available on some plarforms like old android, so just using
2387 // log(x)/log(2) here.
2388 if (operandArray[i].getFConst() <= 0.0f)
2389 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2390 diagnostics, &resultArray[i]);
2391 else
2392 {
2393 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2394 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2395 }
2396 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302397
Olli Etuahof119a262016-08-19 15:54:22 +03002398 case EOpSqrt:
2399 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2400 if (operandArray[i].getFConst() < 0.0f)
2401 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2402 diagnostics, &resultArray[i]);
2403 else
2404 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2405 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302406
Olli Etuahof119a262016-08-19 15:54:22 +03002407 case EOpInverseSqrt:
2408 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2409 // so getting the square root first using builtin function sqrt() and then taking
2410 // its inverse.
2411 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2412 // result to 0.
2413 if (operandArray[i].getFConst() <= 0.0f)
2414 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2415 diagnostics, &resultArray[i]);
2416 else
2417 {
2418 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2419 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2420 }
2421 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302422
Olli Etuahod68924e2017-01-02 17:34:40 +00002423 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002424 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302425 resultArray[i].setBConst(!operandArray[i].getBConst());
2426 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302427
Olli Etuahof119a262016-08-19 15:54:22 +03002428 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302429 {
Olli Etuahof119a262016-08-19 15:54:22 +03002430 ASSERT(getType().getBasicType() == EbtFloat);
2431 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302432 float length = VectorLength(operandArray, objectSize);
2433 if (length)
2434 resultArray[i].setFConst(x / length);
2435 else
Olli Etuahof119a262016-08-19 15:54:22 +03002436 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2437 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302438 break;
2439 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002440 case EOpBitfieldReverse:
2441 {
2442 uint32_t value;
2443 if (getType().getBasicType() == EbtInt)
2444 {
2445 value = static_cast<uint32_t>(operandArray[i].getIConst());
2446 }
2447 else
2448 {
2449 ASSERT(getType().getBasicType() == EbtUInt);
2450 value = operandArray[i].getUConst();
2451 }
2452 uint32_t result = gl::BitfieldReverse(value);
2453 if (getType().getBasicType() == EbtInt)
2454 {
2455 resultArray[i].setIConst(static_cast<int32_t>(result));
2456 }
2457 else
2458 {
2459 resultArray[i].setUConst(result);
2460 }
2461 break;
2462 }
2463 case EOpBitCount:
2464 {
2465 uint32_t value;
2466 if (getType().getBasicType() == EbtInt)
2467 {
2468 value = static_cast<uint32_t>(operandArray[i].getIConst());
2469 }
2470 else
2471 {
2472 ASSERT(getType().getBasicType() == EbtUInt);
2473 value = operandArray[i].getUConst();
2474 }
2475 int result = gl::BitCount(value);
2476 resultArray[i].setIConst(result);
2477 break;
2478 }
2479 case EOpFindLSB:
2480 {
2481 uint32_t value;
2482 if (getType().getBasicType() == EbtInt)
2483 {
2484 value = static_cast<uint32_t>(operandArray[i].getIConst());
2485 }
2486 else
2487 {
2488 ASSERT(getType().getBasicType() == EbtUInt);
2489 value = operandArray[i].getUConst();
2490 }
2491 resultArray[i].setIConst(gl::FindLSB(value));
2492 break;
2493 }
2494 case EOpFindMSB:
2495 {
2496 uint32_t value;
2497 if (getType().getBasicType() == EbtInt)
2498 {
2499 int intValue = operandArray[i].getIConst();
2500 value = static_cast<uint32_t>(intValue);
2501 if (intValue < 0)
2502 {
2503 // Look for zero instead of one in value. This also handles the intValue ==
2504 // -1 special case, where the return value needs to be -1.
2505 value = ~value;
2506 }
2507 }
2508 else
2509 {
2510 ASSERT(getType().getBasicType() == EbtUInt);
2511 value = operandArray[i].getUConst();
2512 }
2513 resultArray[i].setIConst(gl::FindMSB(value));
2514 break;
2515 }
Olli Etuahof119a262016-08-19 15:54:22 +03002516 case EOpDFdx:
2517 case EOpDFdy:
2518 case EOpFwidth:
2519 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302520 // Derivatives of constant arguments should be 0.
2521 resultArray[i].setFConst(0.0f);
2522 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302523
Olli Etuahof119a262016-08-19 15:54:22 +03002524 default:
2525 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302526 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302527 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002528
Arun Patoleab2b9a22015-07-06 18:27:56 +05302529 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002530}
2531
Olli Etuahof119a262016-08-19 15:54:22 +03002532void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2533 FloatTypeUnaryFunc builtinFunc,
2534 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302535{
2536 ASSERT(builtinFunc);
2537
Olli Etuahof119a262016-08-19 15:54:22 +03002538 ASSERT(getType().getBasicType() == EbtFloat);
2539 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302540}
2541
Jamie Madillb1a85f42014-08-19 15:23:24 -04002542// static
Olli Etuahof119a262016-08-19 15:54:22 +03002543TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002544{
2545 ASSERT(aggregate->getSequence()->size() > 0u);
2546 size_t resultSize = aggregate->getType().getObjectSize();
2547 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2548 TBasicType basicType = aggregate->getBasicType();
2549
2550 size_t resultIndex = 0u;
2551
2552 if (aggregate->getSequence()->size() == 1u)
2553 {
2554 TIntermNode *argument = aggregate->getSequence()->front();
2555 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2556 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2557 // Check the special case of constructing a matrix diagonal from a single scalar,
2558 // or a vector from a single scalar.
2559 if (argumentConstant->getType().getObjectSize() == 1u)
2560 {
2561 if (aggregate->isMatrix())
2562 {
2563 int resultCols = aggregate->getType().getCols();
2564 int resultRows = aggregate->getType().getRows();
2565 for (int col = 0; col < resultCols; ++col)
2566 {
2567 for (int row = 0; row < resultRows; ++row)
2568 {
2569 if (col == row)
2570 {
2571 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2572 }
2573 else
2574 {
2575 resultArray[resultIndex].setFConst(0.0f);
2576 }
2577 ++resultIndex;
2578 }
2579 }
2580 }
2581 else
2582 {
2583 while (resultIndex < resultSize)
2584 {
2585 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2586 ++resultIndex;
2587 }
2588 }
2589 ASSERT(resultIndex == resultSize);
2590 return resultArray;
2591 }
2592 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2593 {
2594 // The special case of constructing a matrix from a matrix.
2595 int argumentCols = argumentConstant->getType().getCols();
2596 int argumentRows = argumentConstant->getType().getRows();
2597 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002598 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002599 for (int col = 0; col < resultCols; ++col)
2600 {
2601 for (int row = 0; row < resultRows; ++row)
2602 {
2603 if (col < argumentCols && row < argumentRows)
2604 {
2605 resultArray[resultIndex].cast(basicType,
2606 argumentUnionArray[col * argumentRows + row]);
2607 }
2608 else if (col == row)
2609 {
2610 resultArray[resultIndex].setFConst(1.0f);
2611 }
2612 else
2613 {
2614 resultArray[resultIndex].setFConst(0.0f);
2615 }
2616 ++resultIndex;
2617 }
2618 }
2619 ASSERT(resultIndex == resultSize);
2620 return resultArray;
2621 }
2622 }
2623
2624 for (TIntermNode *&argument : *aggregate->getSequence())
2625 {
2626 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2627 size_t argumentSize = argumentConstant->getType().getObjectSize();
2628 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2629 for (size_t i = 0u; i < argumentSize; ++i)
2630 {
2631 if (resultIndex >= resultSize)
2632 break;
2633 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2634 ++resultIndex;
2635 }
2636 }
2637 ASSERT(resultIndex == resultSize);
2638 return resultArray;
2639}
2640
2641// static
Olli Etuahof119a262016-08-19 15:54:22 +03002642TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2643 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302644{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002645 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002646 TIntermSequence *arguments = aggregate->getSequence();
2647 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2648 std::vector<const TConstantUnion *> unionArrays(argsCount);
2649 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002650 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302651 TBasicType basicType = EbtVoid;
2652 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002653 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302654 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002655 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2656 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302657
2658 if (i == 0)
2659 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002660 basicType = argConstant->getType().getBasicType();
2661 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302662 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002663 unionArrays[i] = argConstant->getUnionArrayPointer();
2664 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002665 if (objectSizes[i] > maxObjectSize)
2666 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302667 }
2668
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002669 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302670 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002671 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302672 if (objectSizes[i] != maxObjectSize)
2673 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2674 }
Arun Patole274f0702015-05-05 13:33:30 +05302675
Olli Etuahob43846e2015-06-02 18:18:57 +03002676 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002677
2678 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302679 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002680 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302681 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002682 ASSERT(basicType == EbtFloat);
2683 resultArray = new TConstantUnion[maxObjectSize];
2684 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302685 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002686 float y = unionArrays[0][i].getFConst();
2687 float x = unionArrays[1][i].getFConst();
2688 // Results are undefined if x and y are both 0.
2689 if (x == 0.0f && y == 0.0f)
2690 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2691 else
2692 resultArray[i].setFConst(atan2f(y, x));
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 EOpPow:
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 // Results are undefined if x < 0.
2706 // Results are undefined if x = 0 and y <= 0.
2707 if (x < 0.0f)
2708 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2709 else if (x == 0.0f && y <= 0.0f)
2710 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2711 else
2712 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302713 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002714 break;
2715 }
Arun Patolebf790422015-05-18 17:53:04 +05302716
Olli Etuaho51182ab2017-01-22 00:12:29 +00002717 case EOpMod:
2718 {
2719 ASSERT(basicType == EbtFloat);
2720 resultArray = new TConstantUnion[maxObjectSize];
2721 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302722 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002723 float x = unionArrays[0][i].getFConst();
2724 float y = unionArrays[1][i].getFConst();
2725 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302726 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002727 break;
2728 }
Arun Patolebf790422015-05-18 17:53:04 +05302729
Olli Etuaho51182ab2017-01-22 00:12:29 +00002730 case EOpMin:
2731 {
2732 resultArray = new TConstantUnion[maxObjectSize];
2733 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302734 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002735 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302736 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002737 case EbtFloat:
2738 resultArray[i].setFConst(
2739 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2740 break;
2741 case EbtInt:
2742 resultArray[i].setIConst(
2743 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2744 break;
2745 case EbtUInt:
2746 resultArray[i].setUConst(
2747 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2748 break;
2749 default:
2750 UNREACHABLE();
2751 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302752 }
2753 }
2754 break;
Arun Patole274f0702015-05-05 13:33:30 +05302755 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002756
2757 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302758 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002759 resultArray = new TConstantUnion[maxObjectSize];
2760 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302761 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002762 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302763 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002764 case EbtFloat:
2765 resultArray[i].setFConst(
2766 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2767 break;
2768 case EbtInt:
2769 resultArray[i].setIConst(
2770 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2771 break;
2772 case EbtUInt:
2773 resultArray[i].setUConst(
2774 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2775 break;
2776 default:
2777 UNREACHABLE();
2778 break;
Arun Patole274f0702015-05-05 13:33:30 +05302779 }
2780 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002781 break;
Arun Patole274f0702015-05-05 13:33:30 +05302782 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002783
2784 case EOpStep:
2785 {
2786 ASSERT(basicType == EbtFloat);
2787 resultArray = new TConstantUnion[maxObjectSize];
2788 for (size_t i = 0; i < maxObjectSize; i++)
2789 resultArray[i].setFConst(
2790 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2791 break;
2792 }
2793
2794 case EOpLessThanComponentWise:
2795 {
2796 resultArray = new TConstantUnion[maxObjectSize];
2797 for (size_t i = 0; i < maxObjectSize; i++)
2798 {
2799 switch (basicType)
2800 {
2801 case EbtFloat:
2802 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2803 unionArrays[1][i].getFConst());
2804 break;
2805 case EbtInt:
2806 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2807 unionArrays[1][i].getIConst());
2808 break;
2809 case EbtUInt:
2810 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2811 unionArrays[1][i].getUConst());
2812 break;
2813 default:
2814 UNREACHABLE();
2815 break;
2816 }
2817 }
2818 break;
2819 }
2820
2821 case EOpLessThanEqualComponentWise:
2822 {
2823 resultArray = new TConstantUnion[maxObjectSize];
2824 for (size_t i = 0; i < maxObjectSize; i++)
2825 {
2826 switch (basicType)
2827 {
2828 case EbtFloat:
2829 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2830 unionArrays[1][i].getFConst());
2831 break;
2832 case EbtInt:
2833 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2834 unionArrays[1][i].getIConst());
2835 break;
2836 case EbtUInt:
2837 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2838 unionArrays[1][i].getUConst());
2839 break;
2840 default:
2841 UNREACHABLE();
2842 break;
2843 }
2844 }
2845 break;
2846 }
2847
2848 case EOpGreaterThanComponentWise:
2849 {
2850 resultArray = new TConstantUnion[maxObjectSize];
2851 for (size_t i = 0; i < maxObjectSize; i++)
2852 {
2853 switch (basicType)
2854 {
2855 case EbtFloat:
2856 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2857 unionArrays[1][i].getFConst());
2858 break;
2859 case EbtInt:
2860 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2861 unionArrays[1][i].getIConst());
2862 break;
2863 case EbtUInt:
2864 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2865 unionArrays[1][i].getUConst());
2866 break;
2867 default:
2868 UNREACHABLE();
2869 break;
2870 }
2871 }
2872 break;
2873 }
2874 case EOpGreaterThanEqualComponentWise:
2875 {
2876 resultArray = new TConstantUnion[maxObjectSize];
2877 for (size_t i = 0; i < maxObjectSize; i++)
2878 {
2879 switch (basicType)
2880 {
2881 case EbtFloat:
2882 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2883 unionArrays[1][i].getFConst());
2884 break;
2885 case EbtInt:
2886 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2887 unionArrays[1][i].getIConst());
2888 break;
2889 case EbtUInt:
2890 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2891 unionArrays[1][i].getUConst());
2892 break;
2893 default:
2894 UNREACHABLE();
2895 break;
2896 }
2897 }
2898 }
2899 break;
2900
2901 case EOpEqualComponentWise:
2902 {
2903 resultArray = new TConstantUnion[maxObjectSize];
2904 for (size_t i = 0; i < maxObjectSize; i++)
2905 {
2906 switch (basicType)
2907 {
2908 case EbtFloat:
2909 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2910 unionArrays[1][i].getFConst());
2911 break;
2912 case EbtInt:
2913 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2914 unionArrays[1][i].getIConst());
2915 break;
2916 case EbtUInt:
2917 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2918 unionArrays[1][i].getUConst());
2919 break;
2920 case EbtBool:
2921 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2922 unionArrays[1][i].getBConst());
2923 break;
2924 default:
2925 UNREACHABLE();
2926 break;
2927 }
2928 }
2929 break;
2930 }
2931
2932 case EOpNotEqualComponentWise:
2933 {
2934 resultArray = new TConstantUnion[maxObjectSize];
2935 for (size_t i = 0; i < maxObjectSize; i++)
2936 {
2937 switch (basicType)
2938 {
2939 case EbtFloat:
2940 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2941 unionArrays[1][i].getFConst());
2942 break;
2943 case EbtInt:
2944 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2945 unionArrays[1][i].getIConst());
2946 break;
2947 case EbtUInt:
2948 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2949 unionArrays[1][i].getUConst());
2950 break;
2951 case EbtBool:
2952 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2953 unionArrays[1][i].getBConst());
2954 break;
2955 default:
2956 UNREACHABLE();
2957 break;
2958 }
2959 }
2960 break;
2961 }
2962
2963 case EOpDistance:
2964 {
2965 ASSERT(basicType == EbtFloat);
2966 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2967 resultArray = new TConstantUnion();
2968 for (size_t i = 0; i < maxObjectSize; i++)
2969 {
2970 float x = unionArrays[0][i].getFConst();
2971 float y = unionArrays[1][i].getFConst();
2972 distanceArray[i].setFConst(x - y);
2973 }
2974 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2975 break;
2976 }
2977
2978 case EOpDot:
2979 ASSERT(basicType == EbtFloat);
2980 resultArray = new TConstantUnion();
2981 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2982 break;
2983
2984 case EOpCross:
2985 {
2986 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2987 resultArray = new TConstantUnion[maxObjectSize];
2988 float x0 = unionArrays[0][0].getFConst();
2989 float x1 = unionArrays[0][1].getFConst();
2990 float x2 = unionArrays[0][2].getFConst();
2991 float y0 = unionArrays[1][0].getFConst();
2992 float y1 = unionArrays[1][1].getFConst();
2993 float y2 = unionArrays[1][2].getFConst();
2994 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2995 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2996 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2997 break;
2998 }
2999
3000 case EOpReflect:
3001 {
3002 ASSERT(basicType == EbtFloat);
3003 // genType reflect (genType I, genType N) :
3004 // For the incident vector I and surface orientation N, returns the reflection
3005 // direction:
3006 // I - 2 * dot(N, I) * N.
3007 resultArray = new TConstantUnion[maxObjectSize];
3008 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3009 for (size_t i = 0; i < maxObjectSize; i++)
3010 {
3011 float result = unionArrays[0][i].getFConst() -
3012 2.0f * dotProduct * unionArrays[1][i].getFConst();
3013 resultArray[i].setFConst(result);
3014 }
3015 break;
3016 }
3017
3018 case EOpMulMatrixComponentWise:
3019 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003020 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3021 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003022 // Perform component-wise matrix multiplication.
3023 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003024 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003025 angle::Matrix<float> result =
3026 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3027 SetUnionArrayFromMatrix(result, resultArray);
3028 break;
3029 }
3030
3031 case EOpOuterProduct:
3032 {
3033 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003034 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3035 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003036 resultArray = new TConstantUnion[numRows * numCols];
3037 angle::Matrix<float> result =
3038 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3039 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3040 SetUnionArrayFromMatrix(result, resultArray);
3041 break;
3042 }
3043
3044 case EOpClamp:
3045 {
3046 resultArray = new TConstantUnion[maxObjectSize];
3047 for (size_t i = 0; i < maxObjectSize; i++)
3048 {
3049 switch (basicType)
3050 {
3051 case EbtFloat:
3052 {
3053 float x = unionArrays[0][i].getFConst();
3054 float min = unionArrays[1][i].getFConst();
3055 float max = unionArrays[2][i].getFConst();
3056 // Results are undefined if min > max.
3057 if (min > max)
3058 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3059 &resultArray[i]);
3060 else
3061 resultArray[i].setFConst(gl::clamp(x, min, max));
3062 break;
3063 }
3064
3065 case EbtInt:
3066 {
3067 int x = unionArrays[0][i].getIConst();
3068 int min = unionArrays[1][i].getIConst();
3069 int max = unionArrays[2][i].getIConst();
3070 // Results are undefined if min > max.
3071 if (min > max)
3072 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3073 &resultArray[i]);
3074 else
3075 resultArray[i].setIConst(gl::clamp(x, min, max));
3076 break;
3077 }
3078 case EbtUInt:
3079 {
3080 unsigned int x = unionArrays[0][i].getUConst();
3081 unsigned int min = unionArrays[1][i].getUConst();
3082 unsigned int max = unionArrays[2][i].getUConst();
3083 // Results are undefined if min > max.
3084 if (min > max)
3085 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3086 &resultArray[i]);
3087 else
3088 resultArray[i].setUConst(gl::clamp(x, min, max));
3089 break;
3090 }
3091 default:
3092 UNREACHABLE();
3093 break;
3094 }
3095 }
3096 break;
3097 }
3098
3099 case EOpMix:
3100 {
3101 ASSERT(basicType == EbtFloat);
3102 resultArray = new TConstantUnion[maxObjectSize];
3103 for (size_t i = 0; i < maxObjectSize; i++)
3104 {
3105 float x = unionArrays[0][i].getFConst();
3106 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003107 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003108 if (type == EbtFloat)
3109 {
3110 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3111 float a = unionArrays[2][i].getFConst();
3112 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3113 }
3114 else // 3rd parameter is EbtBool
3115 {
3116 ASSERT(type == EbtBool);
3117 // Selects which vector each returned component comes from.
3118 // For a component of a that is false, the corresponding component of x is
3119 // returned.
3120 // For a component of a that is true, the corresponding component of y is
3121 // returned.
3122 bool a = unionArrays[2][i].getBConst();
3123 resultArray[i].setFConst(a ? y : x);
3124 }
3125 }
3126 break;
3127 }
3128
3129 case EOpSmoothStep:
3130 {
3131 ASSERT(basicType == EbtFloat);
3132 resultArray = new TConstantUnion[maxObjectSize];
3133 for (size_t i = 0; i < maxObjectSize; i++)
3134 {
3135 float edge0 = unionArrays[0][i].getFConst();
3136 float edge1 = unionArrays[1][i].getFConst();
3137 float x = unionArrays[2][i].getFConst();
3138 // Results are undefined if edge0 >= edge1.
3139 if (edge0 >= edge1)
3140 {
3141 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3142 }
3143 else
3144 {
3145 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3146 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3147 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3148 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3149 }
3150 }
3151 break;
3152 }
3153
Olli Etuaho74da73f2017-02-01 15:37:48 +00003154 case EOpLdexp:
3155 {
3156 resultArray = new TConstantUnion[maxObjectSize];
3157 for (size_t i = 0; i < maxObjectSize; i++)
3158 {
3159 float x = unionArrays[0][i].getFConst();
3160 int exp = unionArrays[1][i].getIConst();
3161 if (exp > 128)
3162 {
3163 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3164 }
3165 else
3166 {
3167 resultArray[i].setFConst(gl::Ldexp(x, exp));
3168 }
3169 }
3170 break;
3171 }
3172
Olli Etuaho51182ab2017-01-22 00:12:29 +00003173 case EOpFaceForward:
3174 {
3175 ASSERT(basicType == EbtFloat);
3176 // genType faceforward(genType N, genType I, genType Nref) :
3177 // If dot(Nref, I) < 0 return N, otherwise return -N.
3178 resultArray = new TConstantUnion[maxObjectSize];
3179 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3180 for (size_t i = 0; i < maxObjectSize; i++)
3181 {
3182 if (dotProduct < 0)
3183 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3184 else
3185 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3186 }
3187 break;
3188 }
3189
3190 case EOpRefract:
3191 {
3192 ASSERT(basicType == EbtFloat);
3193 // genType refract(genType I, genType N, float eta) :
3194 // For the incident vector I and surface normal N, and the ratio of indices of
3195 // refraction eta,
3196 // return the refraction vector. The result is computed by
3197 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3198 // if (k < 0.0)
3199 // return genType(0.0)
3200 // else
3201 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3202 resultArray = new TConstantUnion[maxObjectSize];
3203 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3204 for (size_t i = 0; i < maxObjectSize; i++)
3205 {
3206 float eta = unionArrays[2][i].getFConst();
3207 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3208 if (k < 0.0f)
3209 resultArray[i].setFConst(0.0f);
3210 else
3211 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3212 (eta * dotProduct + sqrtf(k)) *
3213 unionArrays[1][i].getFConst());
3214 }
3215 break;
3216 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003217 case EOpBitfieldExtract:
3218 {
3219 resultArray = new TConstantUnion[maxObjectSize];
3220 for (size_t i = 0; i < maxObjectSize; ++i)
3221 {
3222 int offset = unionArrays[1][0].getIConst();
3223 int bits = unionArrays[2][0].getIConst();
3224 if (bits == 0)
3225 {
3226 if (aggregate->getBasicType() == EbtInt)
3227 {
3228 resultArray[i].setIConst(0);
3229 }
3230 else
3231 {
3232 ASSERT(aggregate->getBasicType() == EbtUInt);
3233 resultArray[i].setUConst(0);
3234 }
3235 }
3236 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3237 {
3238 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3239 &resultArray[i]);
3240 }
3241 else
3242 {
3243 // bits can be 32 here, so we need to avoid bit shift overflow.
3244 uint32_t maskMsb = 1u << (bits - 1);
3245 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3246 if (aggregate->getBasicType() == EbtInt)
3247 {
3248 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3249 uint32_t resultUnsigned = (value & mask) >> offset;
3250 if ((resultUnsigned & maskMsb) != 0)
3251 {
3252 // The most significant bits (from bits+1 to the most significant bit)
3253 // should be set to 1.
3254 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3255 resultUnsigned |= higherBitsMask;
3256 }
3257 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3258 }
3259 else
3260 {
3261 ASSERT(aggregate->getBasicType() == EbtUInt);
3262 uint32_t value = unionArrays[0][i].getUConst();
3263 resultArray[i].setUConst((value & mask) >> offset);
3264 }
3265 }
3266 }
3267 break;
3268 }
3269 case EOpBitfieldInsert:
3270 {
3271 resultArray = new TConstantUnion[maxObjectSize];
3272 for (size_t i = 0; i < maxObjectSize; ++i)
3273 {
3274 int offset = unionArrays[2][0].getIConst();
3275 int bits = unionArrays[3][0].getIConst();
3276 if (bits == 0)
3277 {
3278 if (aggregate->getBasicType() == EbtInt)
3279 {
3280 int32_t base = unionArrays[0][i].getIConst();
3281 resultArray[i].setIConst(base);
3282 }
3283 else
3284 {
3285 ASSERT(aggregate->getBasicType() == EbtUInt);
3286 uint32_t base = unionArrays[0][i].getUConst();
3287 resultArray[i].setUConst(base);
3288 }
3289 }
3290 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3291 {
3292 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3293 &resultArray[i]);
3294 }
3295 else
3296 {
3297 // bits can be 32 here, so we need to avoid bit shift overflow.
3298 uint32_t maskMsb = 1u << (bits - 1);
3299 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3300 uint32_t baseMask = ~insertMask;
3301 if (aggregate->getBasicType() == EbtInt)
3302 {
3303 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3304 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3305 uint32_t resultUnsigned =
3306 (base & baseMask) | ((insert << offset) & insertMask);
3307 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3308 }
3309 else
3310 {
3311 ASSERT(aggregate->getBasicType() == EbtUInt);
3312 uint32_t base = unionArrays[0][i].getUConst();
3313 uint32_t insert = unionArrays[1][i].getUConst();
3314 resultArray[i].setUConst((base & baseMask) |
3315 ((insert << offset) & insertMask));
3316 }
3317 }
3318 }
3319 break;
3320 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003321
3322 default:
3323 UNREACHABLE();
3324 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303325 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003326 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303327}
3328
3329// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04003330TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
3331{
Yunchao He4f285442017-04-21 12:15:49 +08003332 if (hashFunction == nullptr || name.empty())
Jamie Madillb1a85f42014-08-19 15:23:24 -04003333 return name;
3334 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
3335 TStringStream stream;
3336 stream << HASHED_NAME_PREFIX << std::hex << number;
3337 TString hashedName = stream.str();
3338 return hashedName;
3339}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003340
3341void TIntermTraverser::updateTree()
3342{
Olli Etuahoa6f22092015-05-08 18:31:10 +03003343 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
3344 {
3345 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
3346 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003347 if (!insertion.insertionsAfter.empty())
3348 {
3349 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
3350 insertion.insertionsAfter);
3351 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003352 }
3353 if (!insertion.insertionsBefore.empty())
3354 {
3355 bool inserted =
3356 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
3357 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003358 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03003359 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003360 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
3361 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003362 const NodeUpdateEntry &replacement = mReplacements[ii];
3363 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003364 bool replaced =
3365 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003366 ASSERT(replaced);
3367
Olli Etuahocd94ef92015-04-16 19:18:10 +03003368 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003369 {
3370 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03003371 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003372 // be replaced, we need to make sure we don't update the replaced
3373 // node; instead, we update the replacement node.
3374 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
3375 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003376 NodeUpdateEntry &replacement2 = mReplacements[jj];
3377 if (replacement2.parent == replacement.original)
3378 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003379 }
3380 }
3381 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003382 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
3383 {
3384 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
3385 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003386 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
3387 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003388 ASSERT(replaced);
3389 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03003390
Jamie Madill03d863c2016-07-27 18:15:53 -04003391 clearReplacementQueue();
3392}
3393
3394void TIntermTraverser::clearReplacementQueue()
3395{
Olli Etuahod4f303e2015-05-20 17:09:06 +03003396 mReplacements.clear();
3397 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04003398 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003399}
Jamie Madill1048e432016-07-23 18:51:28 -04003400
Jamie Madill03d863c2016-07-27 18:15:53 -04003401void TIntermTraverser::queueReplacement(TIntermNode *original,
3402 TIntermNode *replacement,
3403 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003404{
Jamie Madill03d863c2016-07-27 18:15:53 -04003405 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04003406}
3407
Jamie Madill03d863c2016-07-27 18:15:53 -04003408void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
3409 TIntermNode *original,
3410 TIntermNode *replacement,
3411 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003412{
Jamie Madill03d863c2016-07-27 18:15:53 -04003413 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
3414 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04003415}
Jamie Madill45bcc782016-11-07 13:58:48 -05003416
Olli Etuahofe486322017-03-21 09:30:54 +00003417TName TIntermTraverser::GetInternalFunctionName(const char *name)
3418{
3419 TString nameStr(name);
Olli Etuahofe486322017-03-21 09:30:54 +00003420 TName nameObj(nameStr);
3421 nameObj.setInternal(true);
3422 return nameObj;
3423}
3424
3425TIntermFunctionPrototype *TIntermTraverser::CreateInternalFunctionPrototypeNode(
3426 const TType &returnType,
3427 const char *name,
3428 const TSymbolUniqueId &functionId)
3429{
3430 TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType, functionId);
3431 functionNode->getFunctionSymbolInfo()->setNameObj(GetInternalFunctionName(name));
3432 return functionNode;
3433}
3434
3435TIntermFunctionDefinition *TIntermTraverser::CreateInternalFunctionDefinitionNode(
3436 const TType &returnType,
3437 const char *name,
3438 TIntermBlock *functionBody,
3439 const TSymbolUniqueId &functionId)
3440{
3441 TIntermFunctionPrototype *prototypeNode =
3442 CreateInternalFunctionPrototypeNode(returnType, name, functionId);
3443 return new TIntermFunctionDefinition(prototypeNode, functionBody);
3444}
3445
3446TIntermAggregate *TIntermTraverser::CreateInternalFunctionCallNode(
3447 const TType &returnType,
3448 const char *name,
3449 const TSymbolUniqueId &functionId,
3450 TIntermSequence *arguments)
3451{
3452 TIntermAggregate *functionNode = TIntermAggregate::CreateFunctionCall(
3453 returnType, functionId, GetInternalFunctionName(name), arguments);
3454 return functionNode;
3455}
3456
Jamie Madill45bcc782016-11-07 13:58:48 -05003457} // namespace sh