blob: e63848a46708956de2e87de0ea9fe0839df8a902 [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 {
567 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
568
569 size_t size = constType.getObjectSize();
570 TConstantUnion *u = new TConstantUnion[size];
571 for (size_t i = 0; i < size; ++i)
572 {
573 switch (type.getBasicType())
574 {
575 case EbtFloat:
576 u[i].setFConst(0.0f);
577 break;
578 case EbtInt:
579 u[i].setIConst(0);
580 break;
581 case EbtUInt:
582 u[i].setUConst(0u);
583 break;
584 case EbtBool:
585 u[i].setBConst(false);
586 break;
587 default:
Corentin Wallez17a5c062017-01-22 15:20:53 -0500588 // CreateZero is called by ParseContext that keeps parsing even when an error
589 // occurs, so it is possible for CreateZero to be called with non-basic types.
590 // This happens only on error condition but CreateZero needs to return a value
591 // with the correct type to continue the typecheck. That's why we handle
592 // non-basic type by setting whatever value, we just need the type to be right.
593 u[i].setIConst(42);
594 break;
Corentin Wallez509e4562016-08-25 14:55:44 -0400595 }
596 }
597
598 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
599 return node;
600 }
601
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800602 TIntermSequence *arguments = new TIntermSequence();
Corentin Wallez509e4562016-08-25 14:55:44 -0400603
604 if (type.isArray())
605 {
606 TType elementType(type);
607 elementType.clearArrayness();
608
609 size_t arraySize = type.getArraySize();
610 for (size_t i = 0; i < arraySize; ++i)
611 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800612 arguments->push_back(CreateZero(elementType));
Corentin Wallez509e4562016-08-25 14:55:44 -0400613 }
614 }
615 else
616 {
617 ASSERT(type.getBasicType() == EbtStruct);
618
619 TStructure *structure = type.getStruct();
620 for (const auto &field : structure->fields())
621 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800622 arguments->push_back(CreateZero(*field->type()));
Corentin Wallez509e4562016-08-25 14:55:44 -0400623 }
624 }
625
Olli Etuahofe486322017-03-21 09:30:54 +0000626 return TIntermAggregate::CreateConstructor(constType, sh::TypeToConstructorOperator(type),
627 arguments);
Corentin Wallez509e4562016-08-25 14:55:44 -0400628}
629
Corentin Wallez36fd1002016-12-08 11:30:44 -0500630// static
631TIntermTyped *TIntermTyped::CreateBool(bool value)
632{
633 TConstantUnion *u = new TConstantUnion[1];
634 u[0].setBConst(value);
635
636 TType type(EbtBool, EbpUndefined, EvqConst, 1);
637 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
638 return node;
639}
640
Olli Etuahod7a25242015-08-18 13:49:45 +0300641TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
642{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200643 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300644}
645
Olli Etuahobd674552016-10-06 13:28:42 +0100646void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
647{
Olli Etuahoec9232b2017-03-27 17:01:37 +0300648 setName(function.getName());
Olli Etuahofe486322017-03-21 09:30:54 +0000649 setId(TSymbolUniqueId(function));
650}
651
652TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id) : mId(new TSymbolUniqueId(id))
653{
654}
655
656TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
657 : mName(info.mName), mId(nullptr)
658{
659 if (info.mId)
660 {
661 mId = new TSymbolUniqueId(*info.mId);
662 }
663}
664
665TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
666{
667 mName = info.mName;
668 if (info.mId)
669 {
670 mId = new TSymbolUniqueId(*info.mId);
671 }
672 else
673 {
674 mId = nullptr;
675 }
676 return *this;
677}
678
679void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
680{
681 mId = new TSymbolUniqueId(id);
682}
683
684const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
685{
686 ASSERT(mId);
687 return *mId;
Olli Etuahobd674552016-10-06 13:28:42 +0100688}
689
Olli Etuahod7a25242015-08-18 13:49:45 +0300690TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
691 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300692 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100693 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
694 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300695{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800696 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300697 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800698 TIntermTyped *typedArg = arg->getAsTyped();
699 ASSERT(typedArg != nullptr);
700 TIntermTyped *argCopy = typedArg->deepCopy();
701 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300702 }
703}
704
Olli Etuahofe486322017-03-21 09:30:54 +0000705TIntermAggregate *TIntermAggregate::shallowCopy() const
706{
707 TIntermSequence *copySeq = new TIntermSequence();
708 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
709 TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq);
710 *copyNode->getFunctionSymbolInfo() = mFunctionInfo;
711 copyNode->setLine(mLine);
712 return copyNode;
713}
714
Olli Etuahob6fa0432016-09-28 16:28:05 +0100715TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
716{
717 TIntermTyped *operandCopy = node.mOperand->deepCopy();
718 ASSERT(operandCopy != nullptr);
719 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000720 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100721}
722
Olli Etuahod7a25242015-08-18 13:49:45 +0300723TIntermBinary::TIntermBinary(const TIntermBinary &node)
724 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
725{
726 TIntermTyped *leftCopy = node.mLeft->deepCopy();
727 TIntermTyped *rightCopy = node.mRight->deepCopy();
728 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
729 mLeft = leftCopy;
730 mRight = rightCopy;
731}
732
733TIntermUnary::TIntermUnary(const TIntermUnary &node)
734 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
735{
736 TIntermTyped *operandCopy = node.mOperand->deepCopy();
737 ASSERT(operandCopy != nullptr);
738 mOperand = operandCopy;
739}
740
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300741TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300742{
Olli Etuahod7a25242015-08-18 13:49:45 +0300743 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300744 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
745 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300746 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300747 mCondition = conditionCopy;
748 mTrueExpression = trueCopy;
749 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300750}
751
Jamie Madillb1a85f42014-08-19 15:23:24 -0400752bool TIntermOperator::isAssignment() const
753{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300754 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400755}
756
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300757bool TIntermOperator::isMultiplication() const
758{
759 switch (mOp)
760 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500761 case EOpMul:
762 case EOpMatrixTimesMatrix:
763 case EOpMatrixTimesVector:
764 case EOpMatrixTimesScalar:
765 case EOpVectorTimesMatrix:
766 case EOpVectorTimesScalar:
767 return true;
768 default:
769 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300770 }
771}
772
Jamie Madillb1a85f42014-08-19 15:23:24 -0400773//
774// returns true if the operator is for one of the constructors
775//
776bool TIntermOperator::isConstructor() const
777{
778 switch (mOp)
779 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500780 case EOpConstructVec2:
781 case EOpConstructVec3:
782 case EOpConstructVec4:
783 case EOpConstructMat2:
784 case EOpConstructMat2x3:
785 case EOpConstructMat2x4:
786 case EOpConstructMat3x2:
787 case EOpConstructMat3:
788 case EOpConstructMat3x4:
789 case EOpConstructMat4x2:
790 case EOpConstructMat4x3:
791 case EOpConstructMat4:
792 case EOpConstructFloat:
793 case EOpConstructIVec2:
794 case EOpConstructIVec3:
795 case EOpConstructIVec4:
796 case EOpConstructInt:
797 case EOpConstructUVec2:
798 case EOpConstructUVec3:
799 case EOpConstructUVec4:
800 case EOpConstructUInt:
801 case EOpConstructBVec2:
802 case EOpConstructBVec3:
803 case EOpConstructBVec4:
804 case EOpConstructBool:
805 case EOpConstructStruct:
806 return true;
807 default:
808 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400809 }
810}
811
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800812bool TIntermOperator::isFunctionCall() const
813{
814 switch (mOp)
815 {
816 case EOpCallFunctionInAST:
817 case EOpCallBuiltInFunction:
818 case EOpCallInternalRawFunction:
819 return true;
820 default:
821 return false;
822 }
823}
824
Olli Etuaho1dded802016-08-18 18:13:13 +0300825TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
826{
827 if (left.isMatrix())
828 {
829 if (right.isMatrix())
830 {
831 return EOpMatrixTimesMatrix;
832 }
833 else
834 {
835 if (right.isVector())
836 {
837 return EOpMatrixTimesVector;
838 }
839 else
840 {
841 return EOpMatrixTimesScalar;
842 }
843 }
844 }
845 else
846 {
847 if (right.isMatrix())
848 {
849 if (left.isVector())
850 {
851 return EOpVectorTimesMatrix;
852 }
853 else
854 {
855 return EOpMatrixTimesScalar;
856 }
857 }
858 else
859 {
860 // Neither operand is a matrix.
861 if (left.isVector() == right.isVector())
862 {
863 // Leave as component product.
864 return EOpMul;
865 }
866 else
867 {
868 return EOpVectorTimesScalar;
869 }
870 }
871 }
872}
873
874TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
875{
876 if (left.isMatrix())
877 {
878 if (right.isMatrix())
879 {
880 return EOpMatrixTimesMatrixAssign;
881 }
882 else
883 {
884 // right should be scalar, but this may not be validated yet.
885 return EOpMatrixTimesScalarAssign;
886 }
887 }
888 else
889 {
890 if (right.isMatrix())
891 {
892 // Left should be a vector, but this may not be validated yet.
893 return EOpVectorTimesMatrixAssign;
894 }
895 else
896 {
897 // Neither operand is a matrix.
898 if (left.isVector() == right.isVector())
899 {
900 // Leave as component product.
901 return EOpMulAssign;
902 }
903 else
904 {
905 // left should be vector and right should be scalar, but this may not be validated
906 // yet.
907 return EOpVectorTimesScalarAssign;
908 }
909 }
910 }
911}
912
Jamie Madillb1a85f42014-08-19 15:23:24 -0400913//
914// Make sure the type of a unary operator is appropriate for its
915// combination of operation and operand type.
916//
Olli Etuahoa2234302016-08-31 12:05:39 +0300917void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400918{
Olli Etuahoa2234302016-08-31 12:05:39 +0300919 TQualifier resultQualifier = EvqTemporary;
920 if (mOperand->getQualifier() == EvqConst)
921 resultQualifier = EvqConst;
922
923 unsigned char operandPrimarySize =
924 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400925 switch (mOp)
926 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300927 case EOpFloatBitsToInt:
928 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
929 break;
930 case EOpFloatBitsToUint:
931 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
932 break;
933 case EOpIntBitsToFloat:
934 case EOpUintBitsToFloat:
935 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
936 break;
937 case EOpPackSnorm2x16:
938 case EOpPackUnorm2x16:
939 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800940 case EOpPackUnorm4x8:
941 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300942 setType(TType(EbtUInt, EbpHigh, resultQualifier));
943 break;
944 case EOpUnpackSnorm2x16:
945 case EOpUnpackUnorm2x16:
946 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
947 break;
948 case EOpUnpackHalf2x16:
949 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
950 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800951 case EOpUnpackUnorm4x8:
952 case EOpUnpackSnorm4x8:
953 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
954 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300955 case EOpAny:
956 case EOpAll:
957 setType(TType(EbtBool, EbpUndefined, resultQualifier));
958 break;
959 case EOpLength:
960 case EOpDeterminant:
961 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
962 break;
963 case EOpTranspose:
964 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
965 static_cast<unsigned char>(mOperand->getType().getRows()),
966 static_cast<unsigned char>(mOperand->getType().getCols())));
967 break;
968 case EOpIsInf:
969 case EOpIsNan:
970 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
971 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000972 case EOpBitfieldReverse:
973 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
974 break;
975 case EOpBitCount:
976 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
977 break;
978 case EOpFindLSB:
979 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
980 break;
981 case EOpFindMSB:
982 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
983 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300984 default:
985 setType(mOperand->getType());
986 mType.setQualifier(resultQualifier);
987 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400988 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300989}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400990
Olli Etuahob6fa0432016-09-28 16:28:05 +0100991TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
992 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
993 mOperand(operand),
994 mSwizzleOffsets(swizzleOffsets)
995{
996 ASSERT(mSwizzleOffsets.size() <= 4);
997 promote();
998}
999
Olli Etuahoa2234302016-08-31 12:05:39 +03001000TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
1001 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
1002{
1003 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001004}
1005
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001006TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1007 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
1008{
1009 promote();
1010}
1011
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001012TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1013 : TIntermNode(), mSymbol(symbol)
1014{
1015 ASSERT(symbol);
1016 setLine(line);
1017}
1018
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001019TIntermTernary::TIntermTernary(TIntermTyped *cond,
1020 TIntermTyped *trueExpression,
1021 TIntermTyped *falseExpression)
1022 : TIntermTyped(trueExpression->getType()),
1023 mCondition(cond),
1024 mTrueExpression(trueExpression),
1025 mFalseExpression(falseExpression)
1026{
1027 getTypePointer()->setQualifier(
1028 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1029}
1030
1031// static
1032TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1033 TIntermTyped *trueExpression,
1034 TIntermTyped *falseExpression)
1035{
1036 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1037 falseExpression->getQualifier() == EvqConst)
1038 {
1039 return EvqConst;
1040 }
1041 return EvqTemporary;
1042}
1043
Olli Etuahob6fa0432016-09-28 16:28:05 +01001044void TIntermSwizzle::promote()
1045{
1046 TQualifier resultQualifier = EvqTemporary;
1047 if (mOperand->getQualifier() == EvqConst)
1048 resultQualifier = EvqConst;
1049
1050 auto numFields = mSwizzleOffsets.size();
1051 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1052 static_cast<unsigned char>(numFields)));
1053}
1054
1055bool TIntermSwizzle::hasDuplicateOffsets() const
1056{
1057 int offsetCount[4] = {0u, 0u, 0u, 0u};
1058 for (const auto offset : mSwizzleOffsets)
1059 {
1060 offsetCount[offset]++;
1061 if (offsetCount[offset] > 1)
1062 {
1063 return true;
1064 }
1065 }
1066 return false;
1067}
1068
Olli Etuaho09b04a22016-12-15 13:30:26 +00001069bool TIntermSwizzle::offsetsMatch(int offset) const
1070{
1071 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1072}
1073
Olli Etuahob6fa0432016-09-28 16:28:05 +01001074void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1075{
1076 for (const int offset : mSwizzleOffsets)
1077 {
1078 switch (offset)
1079 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001080 case 0:
1081 *out << "x";
1082 break;
1083 case 1:
1084 *out << "y";
1085 break;
1086 case 2:
1087 *out << "z";
1088 break;
1089 case 3:
1090 *out << "w";
1091 break;
1092 default:
1093 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001094 }
1095 }
1096}
1097
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001098TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1099 const TIntermTyped *left,
1100 const TIntermTyped *right)
1101{
1102 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1103 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1104 right->getQualifier() != EvqConst)
1105 {
1106 return EvqTemporary;
1107 }
1108 return EvqConst;
1109}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001110
1111// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001112void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001113{
Olli Etuaho1dded802016-08-18 18:13:13 +03001114 ASSERT(!isMultiplication() ||
1115 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1116
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001117 // Comma is handled as a special case.
1118 if (mOp == EOpComma)
1119 {
1120 setType(mRight->getType());
1121 return;
1122 }
1123
Jamie Madillb1a85f42014-08-19 15:23:24 -04001124 // Base assumption: just make the type the same as the left
1125 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001126 setType(mLeft->getType());
1127
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001128 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001129 // Binary operations results in temporary variables unless both
1130 // operands are const.
1131 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1132 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001133 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001134 getTypePointer()->setQualifier(EvqTemporary);
1135 }
1136
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001137 // Handle indexing ops.
1138 switch (mOp)
1139 {
1140 case EOpIndexDirect:
1141 case EOpIndexIndirect:
1142 if (mLeft->isArray())
1143 {
1144 mType.clearArrayness();
1145 }
1146 else if (mLeft->isMatrix())
1147 {
1148 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1149 static_cast<unsigned char>(mLeft->getRows())));
1150 }
1151 else if (mLeft->isVector())
1152 {
1153 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1154 }
1155 else
1156 {
1157 UNREACHABLE();
1158 }
1159 return;
1160 case EOpIndexDirectStruct:
1161 {
1162 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1163 const int i = mRight->getAsConstantUnion()->getIConst(0);
1164 setType(*fields[i]->type());
1165 getTypePointer()->setQualifier(resultQualifier);
1166 return;
1167 }
1168 case EOpIndexDirectInterfaceBlock:
1169 {
1170 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1171 const int i = mRight->getAsConstantUnion()->getIConst(0);
1172 setType(*fields[i]->type());
1173 getTypePointer()->setQualifier(resultQualifier);
1174 return;
1175 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001176 default:
1177 break;
1178 }
1179
1180 ASSERT(mLeft->isArray() == mRight->isArray());
1181
1182 // The result gets promoted to the highest precision.
1183 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1184 getTypePointer()->setPrecision(higherPrecision);
1185
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001186 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001187
1188 //
1189 // All scalars or structs. Code after this test assumes this case is removed!
1190 //
1191 if (nominalSize == 1)
1192 {
1193 switch (mOp)
1194 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001195 //
1196 // Promote to conditional
1197 //
1198 case EOpEqual:
1199 case EOpNotEqual:
1200 case EOpLessThan:
1201 case EOpGreaterThan:
1202 case EOpLessThanEqual:
1203 case EOpGreaterThanEqual:
1204 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1205 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001206
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001207 //
1208 // And and Or operate on conditionals
1209 //
1210 case EOpLogicalAnd:
1211 case EOpLogicalXor:
1212 case EOpLogicalOr:
1213 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1214 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1215 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001216
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001217 default:
1218 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001219 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001220 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001221 }
1222
1223 // If we reach here, at least one of the operands is vector or matrix.
1224 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001225 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001226
Jamie Madillb1a85f42014-08-19 15:23:24 -04001227 switch (mOp)
1228 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001229 case EOpMul:
1230 break;
1231 case EOpMatrixTimesScalar:
1232 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001233 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001234 setType(TType(basicType, higherPrecision, resultQualifier,
1235 static_cast<unsigned char>(mRight->getCols()),
1236 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001237 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001238 break;
1239 case EOpMatrixTimesVector:
1240 setType(TType(basicType, higherPrecision, resultQualifier,
1241 static_cast<unsigned char>(mLeft->getRows()), 1));
1242 break;
1243 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001244 setType(TType(basicType, higherPrecision, resultQualifier,
1245 static_cast<unsigned char>(mRight->getCols()),
1246 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001247 break;
1248 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001249 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001250 static_cast<unsigned char>(nominalSize), 1));
1251 break;
1252 case EOpVectorTimesMatrix:
1253 setType(TType(basicType, higherPrecision, resultQualifier,
1254 static_cast<unsigned char>(mRight->getCols()), 1));
1255 break;
1256 case EOpMulAssign:
1257 case EOpVectorTimesScalarAssign:
1258 case EOpVectorTimesMatrixAssign:
1259 case EOpMatrixTimesScalarAssign:
1260 case EOpMatrixTimesMatrixAssign:
1261 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1262 break;
1263 case EOpAssign:
1264 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001265 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1266 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1267 break;
1268 case EOpAdd:
1269 case EOpSub:
1270 case EOpDiv:
1271 case EOpIMod:
1272 case EOpBitShiftLeft:
1273 case EOpBitShiftRight:
1274 case EOpBitwiseAnd:
1275 case EOpBitwiseXor:
1276 case EOpBitwiseOr:
1277 case EOpAddAssign:
1278 case EOpSubAssign:
1279 case EOpDivAssign:
1280 case EOpIModAssign:
1281 case EOpBitShiftLeftAssign:
1282 case EOpBitShiftRightAssign:
1283 case EOpBitwiseAndAssign:
1284 case EOpBitwiseXorAssign:
1285 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001286 {
1287 const int secondarySize =
1288 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1289 setType(TType(basicType, higherPrecision, resultQualifier,
1290 static_cast<unsigned char>(nominalSize),
1291 static_cast<unsigned char>(secondarySize)));
1292 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001293 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001294 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001295 case EOpEqual:
1296 case EOpNotEqual:
1297 case EOpLessThan:
1298 case EOpGreaterThan:
1299 case EOpLessThanEqual:
1300 case EOpGreaterThanEqual:
1301 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1302 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001303 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001304 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001305
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001306 case EOpIndexDirect:
1307 case EOpIndexIndirect:
1308 case EOpIndexDirectInterfaceBlock:
1309 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001310 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001311 UNREACHABLE();
1312 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001313 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001314 UNREACHABLE();
1315 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001316 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001317}
1318
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001319const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001320{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001321 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001322 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001323 ASSERT(index < static_cast<int>(getType().getArraySize()));
1324 TType arrayElementType = getType();
1325 arrayElementType.clearArrayness();
1326 size_t arrayElementSize = arrayElementType.getObjectSize();
1327 return &mUnionArrayPointer[arrayElementSize * index];
1328 }
1329 else if (isMatrix())
1330 {
1331 ASSERT(index < getType().getCols());
1332 int size = getType().getRows();
1333 return &mUnionArrayPointer[size * index];
1334 }
1335 else if (isVector())
1336 {
1337 ASSERT(index < getType().getNominalSize());
1338 return &mUnionArrayPointer[index];
1339 }
1340 else
1341 {
1342 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001343 return nullptr;
1344 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001345}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001346
Olli Etuahob6fa0432016-09-28 16:28:05 +01001347TIntermTyped *TIntermSwizzle::fold()
1348{
1349 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1350 if (operandConstant == nullptr)
1351 {
1352 return nullptr;
1353 }
1354
1355 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1356 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1357 {
1358 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1359 }
1360 return CreateFoldedNode(constArray, this, mType.getQualifier());
1361}
1362
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001363TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1364{
1365 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1366 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1367 switch (mOp)
1368 {
1369 case EOpIndexDirect:
1370 {
1371 if (leftConstant == nullptr || rightConstant == nullptr)
1372 {
1373 return nullptr;
1374 }
1375 int index = rightConstant->getIConst(0);
1376
1377 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1378 return CreateFoldedNode(constArray, this, mType.getQualifier());
1379 }
1380 case EOpIndexDirectStruct:
1381 {
1382 if (leftConstant == nullptr || rightConstant == nullptr)
1383 {
1384 return nullptr;
1385 }
1386 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1387 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1388
1389 size_t previousFieldsSize = 0;
1390 for (size_t i = 0; i < index; ++i)
1391 {
1392 previousFieldsSize += fields[i]->type()->getObjectSize();
1393 }
1394
1395 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1396 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1397 }
1398 case EOpIndexIndirect:
1399 case EOpIndexDirectInterfaceBlock:
1400 // Can never be constant folded.
1401 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001402 default:
1403 {
1404 if (leftConstant == nullptr || rightConstant == nullptr)
1405 {
1406 return nullptr;
1407 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001408 TConstantUnion *constArray =
1409 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001410
1411 // Nodes may be constant folded without being qualified as constant.
1412 return CreateFoldedNode(constArray, this, mType.getQualifier());
1413 }
1414 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001415}
1416
Olli Etuahof119a262016-08-19 15:54:22 +03001417TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001418{
1419 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1420 if (operandConstant == nullptr)
1421 {
1422 return nullptr;
1423 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301424
1425 TConstantUnion *constArray = nullptr;
1426 switch (mOp)
1427 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001428 case EOpAny:
1429 case EOpAll:
1430 case EOpLength:
1431 case EOpTranspose:
1432 case EOpDeterminant:
1433 case EOpInverse:
1434 case EOpPackSnorm2x16:
1435 case EOpUnpackSnorm2x16:
1436 case EOpPackUnorm2x16:
1437 case EOpUnpackUnorm2x16:
1438 case EOpPackHalf2x16:
1439 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001440 case EOpPackUnorm4x8:
1441 case EOpPackSnorm4x8:
1442 case EOpUnpackUnorm4x8:
1443 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001444 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1445 break;
1446 default:
1447 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1448 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301449 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001450
1451 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001452 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001453}
1454
Olli Etuahof119a262016-08-19 15:54:22 +03001455TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001456{
1457 // Make sure that all params are constant before actual constant folding.
1458 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001459 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001460 if (param->getAsConstantUnion() == nullptr)
1461 {
1462 return nullptr;
1463 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001464 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001465 TConstantUnion *constArray = nullptr;
1466 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001467 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001468 else
Olli Etuahof119a262016-08-19 15:54:22 +03001469 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001470
1471 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001472 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001473}
1474
Jamie Madillb1a85f42014-08-19 15:23:24 -04001475//
1476// The fold functions see if an operation on a constant can be done in place,
1477// without generating run-time code.
1478//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001479// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001480//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001481TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1482 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001483 TDiagnostics *diagnostics,
1484 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001485{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001486 const TConstantUnion *leftArray = getUnionArrayPointer();
1487 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001488
Olli Etuahof119a262016-08-19 15:54:22 +03001489 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001490
1491 size_t objectSize = getType().getObjectSize();
1492
1493 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1494 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1495 {
1496 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1497 }
1498 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1499 {
1500 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001501 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001502 objectSize = rightNode->getType().getObjectSize();
1503 }
1504
1505 TConstantUnion *resultArray = nullptr;
1506
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001507 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001508 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001509 case EOpAdd:
1510 resultArray = new TConstantUnion[objectSize];
1511 for (size_t i = 0; i < objectSize; i++)
1512 resultArray[i] =
1513 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1514 break;
1515 case EOpSub:
1516 resultArray = new TConstantUnion[objectSize];
1517 for (size_t i = 0; i < objectSize; i++)
1518 resultArray[i] =
1519 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1520 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001521
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001522 case EOpMul:
1523 case EOpVectorTimesScalar:
1524 case EOpMatrixTimesScalar:
1525 resultArray = new TConstantUnion[objectSize];
1526 for (size_t i = 0; i < objectSize; i++)
1527 resultArray[i] =
1528 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1529 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001530
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001531 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001532 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001533 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001534 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001535
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001536 const int leftCols = getCols();
1537 const int leftRows = getRows();
1538 const int rightCols = rightNode->getType().getCols();
1539 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001540 const int resultCols = rightCols;
1541 const int resultRows = leftRows;
1542
1543 resultArray = new TConstantUnion[resultCols * resultRows];
1544 for (int row = 0; row < resultRows; row++)
1545 {
1546 for (int column = 0; column < resultCols; column++)
1547 {
1548 resultArray[resultRows * column + row].setFConst(0.0f);
1549 for (int i = 0; i < leftCols; i++)
1550 {
1551 resultArray[resultRows * column + row].setFConst(
1552 resultArray[resultRows * column + row].getFConst() +
1553 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001554 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001555 }
1556 }
1557 }
1558 }
1559 break;
1560
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001561 case EOpDiv:
1562 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001563 {
1564 resultArray = new TConstantUnion[objectSize];
1565 for (size_t i = 0; i < objectSize; i++)
1566 {
1567 switch (getType().getBasicType())
1568 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001569 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001570 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001571 ASSERT(op == EOpDiv);
1572 float dividend = leftArray[i].getFConst();
1573 float divisor = rightArray[i].getFConst();
1574 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001575 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001576 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001577 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001578 diagnostics->warning(
1579 getLine(),
1580 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001581 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001582 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001583 }
1584 else
1585 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001586 diagnostics->warning(getLine(),
1587 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001588 bool negativeResult =
1589 std::signbit(dividend) != std::signbit(divisor);
1590 resultArray[i].setFConst(
1591 negativeResult ? -std::numeric_limits<float>::infinity()
1592 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001593 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001594 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001595 else if (gl::isInf(dividend) && gl::isInf(divisor))
1596 {
1597 diagnostics->warning(getLine(),
1598 "Infinity divided by infinity during constant "
1599 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001600 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001601 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1602 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001603 else
1604 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001605 float result = dividend / divisor;
1606 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001607 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001608 diagnostics->warning(
1609 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001610 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001611 }
1612 resultArray[i].setFConst(result);
1613 }
1614 break;
1615 }
1616 case EbtInt:
1617 if (rightArray[i] == 0)
1618 {
1619 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001620 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001621 resultArray[i].setIConst(INT_MAX);
1622 }
1623 else
1624 {
1625 int lhs = leftArray[i].getIConst();
1626 int divisor = rightArray[i].getIConst();
1627 if (op == EOpDiv)
1628 {
1629 // Check for the special case where the minimum representable number
1630 // is
1631 // divided by -1. If left alone this leads to integer overflow in
1632 // C++.
1633 // ESSL 3.00.6 section 4.1.3 Integers:
1634 // "However, for the case where the minimum representable value is
1635 // divided by -1, it is allowed to return either the minimum
1636 // representable value or the maximum representable value."
1637 if (lhs == -0x7fffffff - 1 && divisor == -1)
1638 {
1639 resultArray[i].setIConst(0x7fffffff);
1640 }
1641 else
1642 {
1643 resultArray[i].setIConst(lhs / divisor);
1644 }
Olli Etuahod4453572016-09-27 13:21:46 +01001645 }
1646 else
1647 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001648 ASSERT(op == EOpIMod);
1649 if (lhs < 0 || divisor < 0)
1650 {
1651 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1652 // when
1653 // either one of the operands is negative.
1654 diagnostics->warning(getLine(),
1655 "Negative modulus operator operand "
1656 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001657 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001658 resultArray[i].setIConst(0);
1659 }
1660 else
1661 {
1662 resultArray[i].setIConst(lhs % divisor);
1663 }
Olli Etuahod4453572016-09-27 13:21:46 +01001664 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001665 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001666 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001667
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001668 case EbtUInt:
1669 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001670 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001671 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001672 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001673 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001674 }
1675 else
1676 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001677 if (op == EOpDiv)
1678 {
1679 resultArray[i].setUConst(leftArray[i].getUConst() /
1680 rightArray[i].getUConst());
1681 }
1682 else
1683 {
1684 ASSERT(op == EOpIMod);
1685 resultArray[i].setUConst(leftArray[i].getUConst() %
1686 rightArray[i].getUConst());
1687 }
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 default:
1692 UNREACHABLE();
1693 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001694 }
1695 }
1696 }
1697 break;
1698
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001699 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001700 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001701 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001702 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001703
1704 const int matrixCols = getCols();
1705 const int matrixRows = getRows();
1706
1707 resultArray = new TConstantUnion[matrixRows];
1708
1709 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1710 {
1711 resultArray[matrixRow].setFConst(0.0f);
1712 for (int col = 0; col < matrixCols; col++)
1713 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001714 resultArray[matrixRow].setFConst(
1715 resultArray[matrixRow].getFConst() +
1716 leftArray[col * matrixRows + matrixRow].getFConst() *
1717 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001718 }
1719 }
1720 }
1721 break;
1722
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001723 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001724 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001725 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001726 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001727
1728 const int matrixCols = rightNode->getType().getCols();
1729 const int matrixRows = rightNode->getType().getRows();
1730
1731 resultArray = new TConstantUnion[matrixCols];
1732
1733 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1734 {
1735 resultArray[matrixCol].setFConst(0.0f);
1736 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1737 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001738 resultArray[matrixCol].setFConst(
1739 resultArray[matrixCol].getFConst() +
1740 leftArray[matrixRow].getFConst() *
1741 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001742 }
1743 }
1744 }
1745 break;
1746
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001747 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001748 {
1749 resultArray = new TConstantUnion[objectSize];
1750 for (size_t i = 0; i < objectSize; i++)
1751 {
1752 resultArray[i] = leftArray[i] && rightArray[i];
1753 }
1754 }
1755 break;
1756
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001757 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001758 {
1759 resultArray = new TConstantUnion[objectSize];
1760 for (size_t i = 0; i < objectSize; i++)
1761 {
1762 resultArray[i] = leftArray[i] || rightArray[i];
1763 }
1764 }
1765 break;
1766
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001767 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001768 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001769 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001770 resultArray = new TConstantUnion[objectSize];
1771 for (size_t i = 0; i < objectSize; i++)
1772 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001773 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001774 }
1775 }
1776 break;
1777
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001778 case EOpBitwiseAnd:
1779 resultArray = new TConstantUnion[objectSize];
1780 for (size_t i = 0; i < objectSize; i++)
1781 resultArray[i] = leftArray[i] & rightArray[i];
1782 break;
1783 case EOpBitwiseXor:
1784 resultArray = new TConstantUnion[objectSize];
1785 for (size_t i = 0; i < objectSize; i++)
1786 resultArray[i] = leftArray[i] ^ rightArray[i];
1787 break;
1788 case EOpBitwiseOr:
1789 resultArray = new TConstantUnion[objectSize];
1790 for (size_t i = 0; i < objectSize; i++)
1791 resultArray[i] = leftArray[i] | rightArray[i];
1792 break;
1793 case EOpBitShiftLeft:
1794 resultArray = new TConstantUnion[objectSize];
1795 for (size_t i = 0; i < objectSize; i++)
1796 resultArray[i] =
1797 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1798 break;
1799 case EOpBitShiftRight:
1800 resultArray = new TConstantUnion[objectSize];
1801 for (size_t i = 0; i < objectSize; i++)
1802 resultArray[i] =
1803 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1804 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001805
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001806 case EOpLessThan:
1807 ASSERT(objectSize == 1);
1808 resultArray = new TConstantUnion[1];
1809 resultArray->setBConst(*leftArray < *rightArray);
1810 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001811
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001812 case EOpGreaterThan:
1813 ASSERT(objectSize == 1);
1814 resultArray = new TConstantUnion[1];
1815 resultArray->setBConst(*leftArray > *rightArray);
1816 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001817
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001818 case EOpLessThanEqual:
1819 ASSERT(objectSize == 1);
1820 resultArray = new TConstantUnion[1];
1821 resultArray->setBConst(!(*leftArray > *rightArray));
1822 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001823
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001824 case EOpGreaterThanEqual:
1825 ASSERT(objectSize == 1);
1826 resultArray = new TConstantUnion[1];
1827 resultArray->setBConst(!(*leftArray < *rightArray));
1828 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001829
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001830 case EOpEqual:
1831 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001832 {
1833 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001834 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001835 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001836 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001837 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001838 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001839 equal = false;
1840 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001841 }
1842 }
1843 if (op == EOpEqual)
1844 {
1845 resultArray->setBConst(equal);
1846 }
1847 else
1848 {
1849 resultArray->setBConst(!equal);
1850 }
1851 }
1852 break;
1853
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001854 default:
1855 UNREACHABLE();
1856 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001857 }
1858 return resultArray;
1859}
1860
Olli Etuahof119a262016-08-19 15:54:22 +03001861// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1862// code. Returns the constant value to keep using. Nullptr should not be returned.
1863TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001864{
Olli Etuahof119a262016-08-19 15:54:22 +03001865 // Do operations where the return type may have a different number of components compared to the
1866 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001867
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001868 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001869 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301870
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001871 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301872 TConstantUnion *resultArray = nullptr;
1873 switch (op)
1874 {
Olli Etuahof119a262016-08-19 15:54:22 +03001875 case EOpAny:
1876 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301877 resultArray = new TConstantUnion();
1878 resultArray->setBConst(false);
1879 for (size_t i = 0; i < objectSize; i++)
1880 {
1881 if (operandArray[i].getBConst())
1882 {
1883 resultArray->setBConst(true);
1884 break;
1885 }
1886 }
1887 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301888
Olli Etuahof119a262016-08-19 15:54:22 +03001889 case EOpAll:
1890 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301891 resultArray = new TConstantUnion();
1892 resultArray->setBConst(true);
1893 for (size_t i = 0; i < objectSize; i++)
1894 {
1895 if (!operandArray[i].getBConst())
1896 {
1897 resultArray->setBConst(false);
1898 break;
1899 }
1900 }
1901 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301902
Olli Etuahof119a262016-08-19 15:54:22 +03001903 case EOpLength:
1904 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301905 resultArray = new TConstantUnion();
1906 resultArray->setFConst(VectorLength(operandArray, objectSize));
1907 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301908
Olli Etuahof119a262016-08-19 15:54:22 +03001909 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301910 {
Olli Etuahof119a262016-08-19 15:54:22 +03001911 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301912 resultArray = new TConstantUnion[objectSize];
1913 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001914 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301915 SetUnionArrayFromMatrix(result, resultArray);
1916 break;
1917 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301918
Olli Etuahof119a262016-08-19 15:54:22 +03001919 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301920 {
Olli Etuahof119a262016-08-19 15:54:22 +03001921 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301922 unsigned int size = getType().getNominalSize();
1923 ASSERT(size >= 2 && size <= 4);
1924 resultArray = new TConstantUnion();
1925 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1926 break;
1927 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301928
Olli Etuahof119a262016-08-19 15:54:22 +03001929 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301930 {
Olli Etuahof119a262016-08-19 15:54:22 +03001931 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301932 unsigned int size = getType().getNominalSize();
1933 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001934 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301935 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1936 SetUnionArrayFromMatrix(result, resultArray);
1937 break;
1938 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301939
Olli Etuahof119a262016-08-19 15:54:22 +03001940 case EOpPackSnorm2x16:
1941 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301942 ASSERT(getType().getNominalSize() == 2);
1943 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001944 resultArray->setUConst(
1945 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301946 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301947
Olli Etuahof119a262016-08-19 15:54:22 +03001948 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301949 {
Olli Etuahof119a262016-08-19 15:54:22 +03001950 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301951 resultArray = new TConstantUnion[2];
1952 float f1, f2;
1953 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1954 resultArray[0].setFConst(f1);
1955 resultArray[1].setFConst(f2);
1956 break;
1957 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301958
Olli Etuahof119a262016-08-19 15:54:22 +03001959 case EOpPackUnorm2x16:
1960 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301961 ASSERT(getType().getNominalSize() == 2);
1962 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001963 resultArray->setUConst(
1964 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301965 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301966
Olli Etuahof119a262016-08-19 15:54:22 +03001967 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301968 {
Olli Etuahof119a262016-08-19 15:54:22 +03001969 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301970 resultArray = new TConstantUnion[2];
1971 float f1, f2;
1972 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1973 resultArray[0].setFConst(f1);
1974 resultArray[1].setFConst(f2);
1975 break;
1976 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301977
Olli Etuahof119a262016-08-19 15:54:22 +03001978 case EOpPackHalf2x16:
1979 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301980 ASSERT(getType().getNominalSize() == 2);
1981 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001982 resultArray->setUConst(
1983 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301984 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301985
Olli Etuahof119a262016-08-19 15:54:22 +03001986 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301987 {
Olli Etuahof119a262016-08-19 15:54:22 +03001988 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301989 resultArray = new TConstantUnion[2];
1990 float f1, f2;
1991 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1992 resultArray[0].setFConst(f1);
1993 resultArray[1].setFConst(f2);
1994 break;
1995 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301996
Olli Etuaho25aef452017-01-29 16:15:44 -08001997 case EOpPackUnorm4x8:
1998 {
1999 ASSERT(getType().getBasicType() == EbtFloat);
2000 resultArray = new TConstantUnion();
2001 resultArray->setUConst(
2002 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2003 operandArray[2].getFConst(), operandArray[3].getFConst()));
2004 break;
2005 }
2006 case EOpPackSnorm4x8:
2007 {
2008 ASSERT(getType().getBasicType() == EbtFloat);
2009 resultArray = new TConstantUnion();
2010 resultArray->setUConst(
2011 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2012 operandArray[2].getFConst(), operandArray[3].getFConst()));
2013 break;
2014 }
2015 case EOpUnpackUnorm4x8:
2016 {
2017 ASSERT(getType().getBasicType() == EbtUInt);
2018 resultArray = new TConstantUnion[4];
2019 float f[4];
2020 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2021 for (size_t i = 0; i < 4; ++i)
2022 {
2023 resultArray[i].setFConst(f[i]);
2024 }
2025 break;
2026 }
2027 case EOpUnpackSnorm4x8:
2028 {
2029 ASSERT(getType().getBasicType() == EbtUInt);
2030 resultArray = new TConstantUnion[4];
2031 float f[4];
2032 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2033 for (size_t i = 0; i < 4; ++i)
2034 {
2035 resultArray[i].setFConst(f[i]);
2036 }
2037 break;
2038 }
2039
Olli Etuahof119a262016-08-19 15:54:22 +03002040 default:
2041 UNREACHABLE();
2042 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302043 }
2044
2045 return resultArray;
2046}
2047
Olli Etuahof119a262016-08-19 15:54:22 +03002048TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2049 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302050{
Olli Etuahof119a262016-08-19 15:54:22 +03002051 // Do unary operations where each component of the result is computed based on the corresponding
2052 // component of the operand. Also folds normalize, though the divisor in that case takes all
2053 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302054
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002055 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002056 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002057
2058 size_t objectSize = getType().getObjectSize();
2059
Arun Patoleab2b9a22015-07-06 18:27:56 +05302060 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2061 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302062 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002063 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302064 {
Olli Etuahof119a262016-08-19 15:54:22 +03002065 case EOpNegative:
2066 switch (getType().getBasicType())
2067 {
2068 case EbtFloat:
2069 resultArray[i].setFConst(-operandArray[i].getFConst());
2070 break;
2071 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002072 if (operandArray[i] == std::numeric_limits<int>::min())
2073 {
2074 // The minimum representable integer doesn't have a positive
2075 // counterpart, rather the negation overflows and in ESSL is supposed to
2076 // wrap back to the minimum representable integer. Make sure that we
2077 // don't actually let the negation overflow, which has undefined
2078 // behavior in C++.
2079 resultArray[i].setIConst(std::numeric_limits<int>::min());
2080 }
2081 else
2082 {
2083 resultArray[i].setIConst(-operandArray[i].getIConst());
2084 }
Olli Etuahof119a262016-08-19 15:54:22 +03002085 break;
2086 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002087 if (operandArray[i] == 0x80000000u)
2088 {
2089 resultArray[i].setUConst(0x80000000u);
2090 }
2091 else
2092 {
2093 resultArray[i].setUConst(static_cast<unsigned int>(
2094 -static_cast<int>(operandArray[i].getUConst())));
2095 }
Olli Etuahof119a262016-08-19 15:54:22 +03002096 break;
2097 default:
2098 UNREACHABLE();
2099 return nullptr;
2100 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302101 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302102
Olli Etuahof119a262016-08-19 15:54:22 +03002103 case EOpPositive:
2104 switch (getType().getBasicType())
2105 {
2106 case EbtFloat:
2107 resultArray[i].setFConst(operandArray[i].getFConst());
2108 break;
2109 case EbtInt:
2110 resultArray[i].setIConst(operandArray[i].getIConst());
2111 break;
2112 case EbtUInt:
2113 resultArray[i].setUConst(static_cast<unsigned int>(
2114 static_cast<int>(operandArray[i].getUConst())));
2115 break;
2116 default:
2117 UNREACHABLE();
2118 return nullptr;
2119 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302120 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302121
Olli Etuahof119a262016-08-19 15:54:22 +03002122 case EOpLogicalNot:
2123 switch (getType().getBasicType())
2124 {
2125 case EbtBool:
2126 resultArray[i].setBConst(!operandArray[i].getBConst());
2127 break;
2128 default:
2129 UNREACHABLE();
2130 return nullptr;
2131 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302132 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302133
Olli Etuahof119a262016-08-19 15:54:22 +03002134 case EOpBitwiseNot:
2135 switch (getType().getBasicType())
2136 {
2137 case EbtInt:
2138 resultArray[i].setIConst(~operandArray[i].getIConst());
2139 break;
2140 case EbtUInt:
2141 resultArray[i].setUConst(~operandArray[i].getUConst());
2142 break;
2143 default:
2144 UNREACHABLE();
2145 return nullptr;
2146 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302147 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302148
Olli Etuahof119a262016-08-19 15:54:22 +03002149 case EOpRadians:
2150 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302151 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2152 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302153
Olli Etuahof119a262016-08-19 15:54:22 +03002154 case EOpDegrees:
2155 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302156 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2157 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302158
Olli Etuahof119a262016-08-19 15:54:22 +03002159 case EOpSin:
2160 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302161 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302162
Olli Etuahof119a262016-08-19 15:54:22 +03002163 case EOpCos:
2164 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2165 break;
2166
2167 case EOpTan:
2168 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2169 break;
2170
2171 case EOpAsin:
2172 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2173 // 0.
2174 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2175 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2176 diagnostics, &resultArray[i]);
2177 else
2178 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2179 break;
2180
2181 case EOpAcos:
2182 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2183 // 0.
2184 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2185 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2186 diagnostics, &resultArray[i]);
2187 else
2188 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2189 break;
2190
2191 case EOpAtan:
2192 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2193 break;
2194
2195 case EOpSinh:
2196 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2197 break;
2198
2199 case EOpCosh:
2200 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2201 break;
2202
2203 case EOpTanh:
2204 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2205 break;
2206
2207 case EOpAsinh:
2208 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2209 break;
2210
2211 case EOpAcosh:
2212 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2213 if (operandArray[i].getFConst() < 1.0f)
2214 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2215 diagnostics, &resultArray[i]);
2216 else
2217 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2218 break;
2219
2220 case EOpAtanh:
2221 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2222 // 0.
2223 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2224 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2225 diagnostics, &resultArray[i]);
2226 else
2227 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2228 break;
2229
2230 case EOpAbs:
2231 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302232 {
Olli Etuahof119a262016-08-19 15:54:22 +03002233 case EbtFloat:
2234 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2235 break;
2236 case EbtInt:
2237 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2238 break;
2239 default:
2240 UNREACHABLE();
2241 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302242 }
2243 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002244
2245 case EOpSign:
2246 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302247 {
Olli Etuahof119a262016-08-19 15:54:22 +03002248 case EbtFloat:
2249 {
2250 float fConst = operandArray[i].getFConst();
2251 float fResult = 0.0f;
2252 if (fConst > 0.0f)
2253 fResult = 1.0f;
2254 else if (fConst < 0.0f)
2255 fResult = -1.0f;
2256 resultArray[i].setFConst(fResult);
2257 break;
2258 }
2259 case EbtInt:
2260 {
2261 int iConst = operandArray[i].getIConst();
2262 int iResult = 0;
2263 if (iConst > 0)
2264 iResult = 1;
2265 else if (iConst < 0)
2266 iResult = -1;
2267 resultArray[i].setIConst(iResult);
2268 break;
2269 }
2270 default:
2271 UNREACHABLE();
2272 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302273 }
2274 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302275
Olli Etuahof119a262016-08-19 15:54:22 +03002276 case EOpFloor:
2277 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2278 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302279
Olli Etuahof119a262016-08-19 15:54:22 +03002280 case EOpTrunc:
2281 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2282 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302283
Olli Etuahof119a262016-08-19 15:54:22 +03002284 case EOpRound:
2285 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2286 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302287
Olli Etuahof119a262016-08-19 15:54:22 +03002288 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302289 {
Olli Etuahof119a262016-08-19 15:54:22 +03002290 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302291 float x = operandArray[i].getFConst();
2292 float result;
2293 float fractPart = modff(x, &result);
2294 if (fabsf(fractPart) == 0.5f)
2295 result = 2.0f * roundf(x / 2.0f);
2296 else
2297 result = roundf(x);
2298 resultArray[i].setFConst(result);
2299 break;
2300 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302301
Olli Etuahof119a262016-08-19 15:54:22 +03002302 case EOpCeil:
2303 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2304 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302305
Olli Etuahof119a262016-08-19 15:54:22 +03002306 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302307 {
Olli Etuahof119a262016-08-19 15:54:22 +03002308 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302309 float x = operandArray[i].getFConst();
2310 resultArray[i].setFConst(x - floorf(x));
2311 break;
2312 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302313
Olli Etuahof119a262016-08-19 15:54:22 +03002314 case EOpIsNan:
2315 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302316 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2317 break;
Arun Patole551279e2015-07-07 18:18:23 +05302318
Olli Etuahof119a262016-08-19 15:54:22 +03002319 case EOpIsInf:
2320 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302321 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2322 break;
Arun Patole551279e2015-07-07 18:18:23 +05302323
Olli Etuahof119a262016-08-19 15:54:22 +03002324 case EOpFloatBitsToInt:
2325 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302326 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2327 break;
Arun Patole551279e2015-07-07 18:18:23 +05302328
Olli Etuahof119a262016-08-19 15:54:22 +03002329 case EOpFloatBitsToUint:
2330 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302331 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2332 break;
Arun Patole551279e2015-07-07 18:18:23 +05302333
Olli Etuahof119a262016-08-19 15:54:22 +03002334 case EOpIntBitsToFloat:
2335 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302336 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2337 break;
Arun Patole551279e2015-07-07 18:18:23 +05302338
Olli Etuahof119a262016-08-19 15:54:22 +03002339 case EOpUintBitsToFloat:
2340 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302341 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2342 break;
Arun Patole551279e2015-07-07 18:18:23 +05302343
Olli Etuahof119a262016-08-19 15:54:22 +03002344 case EOpExp:
2345 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2346 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302347
Olli Etuahof119a262016-08-19 15:54:22 +03002348 case EOpLog:
2349 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2350 if (operandArray[i].getFConst() <= 0.0f)
2351 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2352 diagnostics, &resultArray[i]);
2353 else
2354 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2355 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302356
Olli Etuahof119a262016-08-19 15:54:22 +03002357 case EOpExp2:
2358 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2359 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302360
Olli Etuahof119a262016-08-19 15:54:22 +03002361 case EOpLog2:
2362 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2363 // And log2f is not available on some plarforms like old android, so just using
2364 // log(x)/log(2) here.
2365 if (operandArray[i].getFConst() <= 0.0f)
2366 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2367 diagnostics, &resultArray[i]);
2368 else
2369 {
2370 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2371 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2372 }
2373 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302374
Olli Etuahof119a262016-08-19 15:54:22 +03002375 case EOpSqrt:
2376 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2377 if (operandArray[i].getFConst() < 0.0f)
2378 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2379 diagnostics, &resultArray[i]);
2380 else
2381 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2382 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302383
Olli Etuahof119a262016-08-19 15:54:22 +03002384 case EOpInverseSqrt:
2385 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2386 // so getting the square root first using builtin function sqrt() and then taking
2387 // its inverse.
2388 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2389 // result to 0.
2390 if (operandArray[i].getFConst() <= 0.0f)
2391 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2392 diagnostics, &resultArray[i]);
2393 else
2394 {
2395 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2396 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2397 }
2398 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302399
Olli Etuahod68924e2017-01-02 17:34:40 +00002400 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002401 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302402 resultArray[i].setBConst(!operandArray[i].getBConst());
2403 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302404
Olli Etuahof119a262016-08-19 15:54:22 +03002405 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302406 {
Olli Etuahof119a262016-08-19 15:54:22 +03002407 ASSERT(getType().getBasicType() == EbtFloat);
2408 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302409 float length = VectorLength(operandArray, objectSize);
2410 if (length)
2411 resultArray[i].setFConst(x / length);
2412 else
Olli Etuahof119a262016-08-19 15:54:22 +03002413 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2414 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302415 break;
2416 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002417 case EOpBitfieldReverse:
2418 {
2419 uint32_t value;
2420 if (getType().getBasicType() == EbtInt)
2421 {
2422 value = static_cast<uint32_t>(operandArray[i].getIConst());
2423 }
2424 else
2425 {
2426 ASSERT(getType().getBasicType() == EbtUInt);
2427 value = operandArray[i].getUConst();
2428 }
2429 uint32_t result = gl::BitfieldReverse(value);
2430 if (getType().getBasicType() == EbtInt)
2431 {
2432 resultArray[i].setIConst(static_cast<int32_t>(result));
2433 }
2434 else
2435 {
2436 resultArray[i].setUConst(result);
2437 }
2438 break;
2439 }
2440 case EOpBitCount:
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 int result = gl::BitCount(value);
2453 resultArray[i].setIConst(result);
2454 break;
2455 }
2456 case EOpFindLSB:
2457 {
2458 uint32_t value;
2459 if (getType().getBasicType() == EbtInt)
2460 {
2461 value = static_cast<uint32_t>(operandArray[i].getIConst());
2462 }
2463 else
2464 {
2465 ASSERT(getType().getBasicType() == EbtUInt);
2466 value = operandArray[i].getUConst();
2467 }
2468 resultArray[i].setIConst(gl::FindLSB(value));
2469 break;
2470 }
2471 case EOpFindMSB:
2472 {
2473 uint32_t value;
2474 if (getType().getBasicType() == EbtInt)
2475 {
2476 int intValue = operandArray[i].getIConst();
2477 value = static_cast<uint32_t>(intValue);
2478 if (intValue < 0)
2479 {
2480 // Look for zero instead of one in value. This also handles the intValue ==
2481 // -1 special case, where the return value needs to be -1.
2482 value = ~value;
2483 }
2484 }
2485 else
2486 {
2487 ASSERT(getType().getBasicType() == EbtUInt);
2488 value = operandArray[i].getUConst();
2489 }
2490 resultArray[i].setIConst(gl::FindMSB(value));
2491 break;
2492 }
Olli Etuahof119a262016-08-19 15:54:22 +03002493 case EOpDFdx:
2494 case EOpDFdy:
2495 case EOpFwidth:
2496 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302497 // Derivatives of constant arguments should be 0.
2498 resultArray[i].setFConst(0.0f);
2499 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302500
Olli Etuahof119a262016-08-19 15:54:22 +03002501 default:
2502 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302503 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302504 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002505
Arun Patoleab2b9a22015-07-06 18:27:56 +05302506 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002507}
2508
Olli Etuahof119a262016-08-19 15:54:22 +03002509void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2510 FloatTypeUnaryFunc builtinFunc,
2511 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302512{
2513 ASSERT(builtinFunc);
2514
Olli Etuahof119a262016-08-19 15:54:22 +03002515 ASSERT(getType().getBasicType() == EbtFloat);
2516 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302517}
2518
Jamie Madillb1a85f42014-08-19 15:23:24 -04002519// static
Olli Etuahof119a262016-08-19 15:54:22 +03002520TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002521{
2522 ASSERT(aggregate->getSequence()->size() > 0u);
2523 size_t resultSize = aggregate->getType().getObjectSize();
2524 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2525 TBasicType basicType = aggregate->getBasicType();
2526
2527 size_t resultIndex = 0u;
2528
2529 if (aggregate->getSequence()->size() == 1u)
2530 {
2531 TIntermNode *argument = aggregate->getSequence()->front();
2532 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2533 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2534 // Check the special case of constructing a matrix diagonal from a single scalar,
2535 // or a vector from a single scalar.
2536 if (argumentConstant->getType().getObjectSize() == 1u)
2537 {
2538 if (aggregate->isMatrix())
2539 {
2540 int resultCols = aggregate->getType().getCols();
2541 int resultRows = aggregate->getType().getRows();
2542 for (int col = 0; col < resultCols; ++col)
2543 {
2544 for (int row = 0; row < resultRows; ++row)
2545 {
2546 if (col == row)
2547 {
2548 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2549 }
2550 else
2551 {
2552 resultArray[resultIndex].setFConst(0.0f);
2553 }
2554 ++resultIndex;
2555 }
2556 }
2557 }
2558 else
2559 {
2560 while (resultIndex < resultSize)
2561 {
2562 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2563 ++resultIndex;
2564 }
2565 }
2566 ASSERT(resultIndex == resultSize);
2567 return resultArray;
2568 }
2569 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2570 {
2571 // The special case of constructing a matrix from a matrix.
2572 int argumentCols = argumentConstant->getType().getCols();
2573 int argumentRows = argumentConstant->getType().getRows();
2574 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002575 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002576 for (int col = 0; col < resultCols; ++col)
2577 {
2578 for (int row = 0; row < resultRows; ++row)
2579 {
2580 if (col < argumentCols && row < argumentRows)
2581 {
2582 resultArray[resultIndex].cast(basicType,
2583 argumentUnionArray[col * argumentRows + row]);
2584 }
2585 else if (col == row)
2586 {
2587 resultArray[resultIndex].setFConst(1.0f);
2588 }
2589 else
2590 {
2591 resultArray[resultIndex].setFConst(0.0f);
2592 }
2593 ++resultIndex;
2594 }
2595 }
2596 ASSERT(resultIndex == resultSize);
2597 return resultArray;
2598 }
2599 }
2600
2601 for (TIntermNode *&argument : *aggregate->getSequence())
2602 {
2603 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2604 size_t argumentSize = argumentConstant->getType().getObjectSize();
2605 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2606 for (size_t i = 0u; i < argumentSize; ++i)
2607 {
2608 if (resultIndex >= resultSize)
2609 break;
2610 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2611 ++resultIndex;
2612 }
2613 }
2614 ASSERT(resultIndex == resultSize);
2615 return resultArray;
2616}
2617
2618// static
Olli Etuahof119a262016-08-19 15:54:22 +03002619TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2620 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302621{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002622 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002623 TIntermSequence *arguments = aggregate->getSequence();
2624 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2625 std::vector<const TConstantUnion *> unionArrays(argsCount);
2626 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002627 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302628 TBasicType basicType = EbtVoid;
2629 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002630 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302631 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002632 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2633 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302634
2635 if (i == 0)
2636 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002637 basicType = argConstant->getType().getBasicType();
2638 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302639 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002640 unionArrays[i] = argConstant->getUnionArrayPointer();
2641 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002642 if (objectSizes[i] > maxObjectSize)
2643 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302644 }
2645
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002646 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302647 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002648 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302649 if (objectSizes[i] != maxObjectSize)
2650 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2651 }
Arun Patole274f0702015-05-05 13:33:30 +05302652
Olli Etuahob43846e2015-06-02 18:18:57 +03002653 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002654
2655 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302656 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002657 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302658 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002659 ASSERT(basicType == EbtFloat);
2660 resultArray = new TConstantUnion[maxObjectSize];
2661 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302662 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002663 float y = unionArrays[0][i].getFConst();
2664 float x = unionArrays[1][i].getFConst();
2665 // Results are undefined if x and y are both 0.
2666 if (x == 0.0f && y == 0.0f)
2667 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2668 else
2669 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302670 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002671 break;
2672 }
Arun Patolebf790422015-05-18 17:53:04 +05302673
Olli Etuaho51182ab2017-01-22 00:12:29 +00002674 case EOpPow:
2675 {
2676 ASSERT(basicType == EbtFloat);
2677 resultArray = new TConstantUnion[maxObjectSize];
2678 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302679 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002680 float x = unionArrays[0][i].getFConst();
2681 float y = unionArrays[1][i].getFConst();
2682 // Results are undefined if x < 0.
2683 // Results are undefined if x = 0 and y <= 0.
2684 if (x < 0.0f)
2685 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2686 else if (x == 0.0f && y <= 0.0f)
2687 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2688 else
2689 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302690 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002691 break;
2692 }
Arun Patolebf790422015-05-18 17:53:04 +05302693
Olli Etuaho51182ab2017-01-22 00:12:29 +00002694 case EOpMod:
2695 {
2696 ASSERT(basicType == EbtFloat);
2697 resultArray = new TConstantUnion[maxObjectSize];
2698 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302699 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002700 float x = unionArrays[0][i].getFConst();
2701 float y = unionArrays[1][i].getFConst();
2702 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302703 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002704 break;
2705 }
Arun Patolebf790422015-05-18 17:53:04 +05302706
Olli Etuaho51182ab2017-01-22 00:12:29 +00002707 case EOpMin:
2708 {
2709 resultArray = new TConstantUnion[maxObjectSize];
2710 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302711 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002712 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302713 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002714 case EbtFloat:
2715 resultArray[i].setFConst(
2716 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2717 break;
2718 case EbtInt:
2719 resultArray[i].setIConst(
2720 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2721 break;
2722 case EbtUInt:
2723 resultArray[i].setUConst(
2724 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2725 break;
2726 default:
2727 UNREACHABLE();
2728 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302729 }
2730 }
2731 break;
Arun Patole274f0702015-05-05 13:33:30 +05302732 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002733
2734 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302735 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002736 resultArray = new TConstantUnion[maxObjectSize];
2737 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302738 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002739 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302740 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002741 case EbtFloat:
2742 resultArray[i].setFConst(
2743 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2744 break;
2745 case EbtInt:
2746 resultArray[i].setIConst(
2747 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2748 break;
2749 case EbtUInt:
2750 resultArray[i].setUConst(
2751 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2752 break;
2753 default:
2754 UNREACHABLE();
2755 break;
Arun Patole274f0702015-05-05 13:33:30 +05302756 }
2757 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002758 break;
Arun Patole274f0702015-05-05 13:33:30 +05302759 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002760
2761 case EOpStep:
2762 {
2763 ASSERT(basicType == EbtFloat);
2764 resultArray = new TConstantUnion[maxObjectSize];
2765 for (size_t i = 0; i < maxObjectSize; i++)
2766 resultArray[i].setFConst(
2767 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2768 break;
2769 }
2770
2771 case EOpLessThanComponentWise:
2772 {
2773 resultArray = new TConstantUnion[maxObjectSize];
2774 for (size_t i = 0; i < maxObjectSize; i++)
2775 {
2776 switch (basicType)
2777 {
2778 case EbtFloat:
2779 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2780 unionArrays[1][i].getFConst());
2781 break;
2782 case EbtInt:
2783 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2784 unionArrays[1][i].getIConst());
2785 break;
2786 case EbtUInt:
2787 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2788 unionArrays[1][i].getUConst());
2789 break;
2790 default:
2791 UNREACHABLE();
2792 break;
2793 }
2794 }
2795 break;
2796 }
2797
2798 case EOpLessThanEqualComponentWise:
2799 {
2800 resultArray = new TConstantUnion[maxObjectSize];
2801 for (size_t i = 0; i < maxObjectSize; i++)
2802 {
2803 switch (basicType)
2804 {
2805 case EbtFloat:
2806 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2807 unionArrays[1][i].getFConst());
2808 break;
2809 case EbtInt:
2810 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2811 unionArrays[1][i].getIConst());
2812 break;
2813 case EbtUInt:
2814 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2815 unionArrays[1][i].getUConst());
2816 break;
2817 default:
2818 UNREACHABLE();
2819 break;
2820 }
2821 }
2822 break;
2823 }
2824
2825 case EOpGreaterThanComponentWise:
2826 {
2827 resultArray = new TConstantUnion[maxObjectSize];
2828 for (size_t i = 0; i < maxObjectSize; i++)
2829 {
2830 switch (basicType)
2831 {
2832 case EbtFloat:
2833 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2834 unionArrays[1][i].getFConst());
2835 break;
2836 case EbtInt:
2837 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2838 unionArrays[1][i].getIConst());
2839 break;
2840 case EbtUInt:
2841 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2842 unionArrays[1][i].getUConst());
2843 break;
2844 default:
2845 UNREACHABLE();
2846 break;
2847 }
2848 }
2849 break;
2850 }
2851 case EOpGreaterThanEqualComponentWise:
2852 {
2853 resultArray = new TConstantUnion[maxObjectSize];
2854 for (size_t i = 0; i < maxObjectSize; i++)
2855 {
2856 switch (basicType)
2857 {
2858 case EbtFloat:
2859 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2860 unionArrays[1][i].getFConst());
2861 break;
2862 case EbtInt:
2863 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2864 unionArrays[1][i].getIConst());
2865 break;
2866 case EbtUInt:
2867 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2868 unionArrays[1][i].getUConst());
2869 break;
2870 default:
2871 UNREACHABLE();
2872 break;
2873 }
2874 }
2875 }
2876 break;
2877
2878 case EOpEqualComponentWise:
2879 {
2880 resultArray = new TConstantUnion[maxObjectSize];
2881 for (size_t i = 0; i < maxObjectSize; i++)
2882 {
2883 switch (basicType)
2884 {
2885 case EbtFloat:
2886 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2887 unionArrays[1][i].getFConst());
2888 break;
2889 case EbtInt:
2890 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2891 unionArrays[1][i].getIConst());
2892 break;
2893 case EbtUInt:
2894 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2895 unionArrays[1][i].getUConst());
2896 break;
2897 case EbtBool:
2898 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2899 unionArrays[1][i].getBConst());
2900 break;
2901 default:
2902 UNREACHABLE();
2903 break;
2904 }
2905 }
2906 break;
2907 }
2908
2909 case EOpNotEqualComponentWise:
2910 {
2911 resultArray = new TConstantUnion[maxObjectSize];
2912 for (size_t i = 0; i < maxObjectSize; i++)
2913 {
2914 switch (basicType)
2915 {
2916 case EbtFloat:
2917 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2918 unionArrays[1][i].getFConst());
2919 break;
2920 case EbtInt:
2921 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2922 unionArrays[1][i].getIConst());
2923 break;
2924 case EbtUInt:
2925 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2926 unionArrays[1][i].getUConst());
2927 break;
2928 case EbtBool:
2929 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2930 unionArrays[1][i].getBConst());
2931 break;
2932 default:
2933 UNREACHABLE();
2934 break;
2935 }
2936 }
2937 break;
2938 }
2939
2940 case EOpDistance:
2941 {
2942 ASSERT(basicType == EbtFloat);
2943 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2944 resultArray = new TConstantUnion();
2945 for (size_t i = 0; i < maxObjectSize; i++)
2946 {
2947 float x = unionArrays[0][i].getFConst();
2948 float y = unionArrays[1][i].getFConst();
2949 distanceArray[i].setFConst(x - y);
2950 }
2951 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2952 break;
2953 }
2954
2955 case EOpDot:
2956 ASSERT(basicType == EbtFloat);
2957 resultArray = new TConstantUnion();
2958 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2959 break;
2960
2961 case EOpCross:
2962 {
2963 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2964 resultArray = new TConstantUnion[maxObjectSize];
2965 float x0 = unionArrays[0][0].getFConst();
2966 float x1 = unionArrays[0][1].getFConst();
2967 float x2 = unionArrays[0][2].getFConst();
2968 float y0 = unionArrays[1][0].getFConst();
2969 float y1 = unionArrays[1][1].getFConst();
2970 float y2 = unionArrays[1][2].getFConst();
2971 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2972 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2973 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2974 break;
2975 }
2976
2977 case EOpReflect:
2978 {
2979 ASSERT(basicType == EbtFloat);
2980 // genType reflect (genType I, genType N) :
2981 // For the incident vector I and surface orientation N, returns the reflection
2982 // direction:
2983 // I - 2 * dot(N, I) * N.
2984 resultArray = new TConstantUnion[maxObjectSize];
2985 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2986 for (size_t i = 0; i < maxObjectSize; i++)
2987 {
2988 float result = unionArrays[0][i].getFConst() -
2989 2.0f * dotProduct * unionArrays[1][i].getFConst();
2990 resultArray[i].setFConst(result);
2991 }
2992 break;
2993 }
2994
2995 case EOpMulMatrixComponentWise:
2996 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002997 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
2998 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00002999 // Perform component-wise matrix multiplication.
3000 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003001 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003002 angle::Matrix<float> result =
3003 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3004 SetUnionArrayFromMatrix(result, resultArray);
3005 break;
3006 }
3007
3008 case EOpOuterProduct:
3009 {
3010 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003011 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3012 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003013 resultArray = new TConstantUnion[numRows * numCols];
3014 angle::Matrix<float> result =
3015 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3016 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3017 SetUnionArrayFromMatrix(result, resultArray);
3018 break;
3019 }
3020
3021 case EOpClamp:
3022 {
3023 resultArray = new TConstantUnion[maxObjectSize];
3024 for (size_t i = 0; i < maxObjectSize; i++)
3025 {
3026 switch (basicType)
3027 {
3028 case EbtFloat:
3029 {
3030 float x = unionArrays[0][i].getFConst();
3031 float min = unionArrays[1][i].getFConst();
3032 float max = unionArrays[2][i].getFConst();
3033 // Results are undefined if min > max.
3034 if (min > max)
3035 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3036 &resultArray[i]);
3037 else
3038 resultArray[i].setFConst(gl::clamp(x, min, max));
3039 break;
3040 }
3041
3042 case EbtInt:
3043 {
3044 int x = unionArrays[0][i].getIConst();
3045 int min = unionArrays[1][i].getIConst();
3046 int max = unionArrays[2][i].getIConst();
3047 // Results are undefined if min > max.
3048 if (min > max)
3049 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3050 &resultArray[i]);
3051 else
3052 resultArray[i].setIConst(gl::clamp(x, min, max));
3053 break;
3054 }
3055 case EbtUInt:
3056 {
3057 unsigned int x = unionArrays[0][i].getUConst();
3058 unsigned int min = unionArrays[1][i].getUConst();
3059 unsigned int max = unionArrays[2][i].getUConst();
3060 // Results are undefined if min > max.
3061 if (min > max)
3062 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3063 &resultArray[i]);
3064 else
3065 resultArray[i].setUConst(gl::clamp(x, min, max));
3066 break;
3067 }
3068 default:
3069 UNREACHABLE();
3070 break;
3071 }
3072 }
3073 break;
3074 }
3075
3076 case EOpMix:
3077 {
3078 ASSERT(basicType == EbtFloat);
3079 resultArray = new TConstantUnion[maxObjectSize];
3080 for (size_t i = 0; i < maxObjectSize; i++)
3081 {
3082 float x = unionArrays[0][i].getFConst();
3083 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003084 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003085 if (type == EbtFloat)
3086 {
3087 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3088 float a = unionArrays[2][i].getFConst();
3089 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3090 }
3091 else // 3rd parameter is EbtBool
3092 {
3093 ASSERT(type == EbtBool);
3094 // Selects which vector each returned component comes from.
3095 // For a component of a that is false, the corresponding component of x is
3096 // returned.
3097 // For a component of a that is true, the corresponding component of y is
3098 // returned.
3099 bool a = unionArrays[2][i].getBConst();
3100 resultArray[i].setFConst(a ? y : x);
3101 }
3102 }
3103 break;
3104 }
3105
3106 case EOpSmoothStep:
3107 {
3108 ASSERT(basicType == EbtFloat);
3109 resultArray = new TConstantUnion[maxObjectSize];
3110 for (size_t i = 0; i < maxObjectSize; i++)
3111 {
3112 float edge0 = unionArrays[0][i].getFConst();
3113 float edge1 = unionArrays[1][i].getFConst();
3114 float x = unionArrays[2][i].getFConst();
3115 // Results are undefined if edge0 >= edge1.
3116 if (edge0 >= edge1)
3117 {
3118 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3119 }
3120 else
3121 {
3122 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3123 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3124 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3125 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3126 }
3127 }
3128 break;
3129 }
3130
Olli Etuaho74da73f2017-02-01 15:37:48 +00003131 case EOpLdexp:
3132 {
3133 resultArray = new TConstantUnion[maxObjectSize];
3134 for (size_t i = 0; i < maxObjectSize; i++)
3135 {
3136 float x = unionArrays[0][i].getFConst();
3137 int exp = unionArrays[1][i].getIConst();
3138 if (exp > 128)
3139 {
3140 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3141 }
3142 else
3143 {
3144 resultArray[i].setFConst(gl::Ldexp(x, exp));
3145 }
3146 }
3147 break;
3148 }
3149
Olli Etuaho51182ab2017-01-22 00:12:29 +00003150 case EOpFaceForward:
3151 {
3152 ASSERT(basicType == EbtFloat);
3153 // genType faceforward(genType N, genType I, genType Nref) :
3154 // If dot(Nref, I) < 0 return N, otherwise return -N.
3155 resultArray = new TConstantUnion[maxObjectSize];
3156 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3157 for (size_t i = 0; i < maxObjectSize; i++)
3158 {
3159 if (dotProduct < 0)
3160 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3161 else
3162 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3163 }
3164 break;
3165 }
3166
3167 case EOpRefract:
3168 {
3169 ASSERT(basicType == EbtFloat);
3170 // genType refract(genType I, genType N, float eta) :
3171 // For the incident vector I and surface normal N, and the ratio of indices of
3172 // refraction eta,
3173 // return the refraction vector. The result is computed by
3174 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3175 // if (k < 0.0)
3176 // return genType(0.0)
3177 // else
3178 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3179 resultArray = new TConstantUnion[maxObjectSize];
3180 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3181 for (size_t i = 0; i < maxObjectSize; i++)
3182 {
3183 float eta = unionArrays[2][i].getFConst();
3184 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3185 if (k < 0.0f)
3186 resultArray[i].setFConst(0.0f);
3187 else
3188 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3189 (eta * dotProduct + sqrtf(k)) *
3190 unionArrays[1][i].getFConst());
3191 }
3192 break;
3193 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003194 case EOpBitfieldExtract:
3195 {
3196 resultArray = new TConstantUnion[maxObjectSize];
3197 for (size_t i = 0; i < maxObjectSize; ++i)
3198 {
3199 int offset = unionArrays[1][0].getIConst();
3200 int bits = unionArrays[2][0].getIConst();
3201 if (bits == 0)
3202 {
3203 if (aggregate->getBasicType() == EbtInt)
3204 {
3205 resultArray[i].setIConst(0);
3206 }
3207 else
3208 {
3209 ASSERT(aggregate->getBasicType() == EbtUInt);
3210 resultArray[i].setUConst(0);
3211 }
3212 }
3213 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3214 {
3215 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3216 &resultArray[i]);
3217 }
3218 else
3219 {
3220 // bits can be 32 here, so we need to avoid bit shift overflow.
3221 uint32_t maskMsb = 1u << (bits - 1);
3222 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3223 if (aggregate->getBasicType() == EbtInt)
3224 {
3225 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3226 uint32_t resultUnsigned = (value & mask) >> offset;
3227 if ((resultUnsigned & maskMsb) != 0)
3228 {
3229 // The most significant bits (from bits+1 to the most significant bit)
3230 // should be set to 1.
3231 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3232 resultUnsigned |= higherBitsMask;
3233 }
3234 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3235 }
3236 else
3237 {
3238 ASSERT(aggregate->getBasicType() == EbtUInt);
3239 uint32_t value = unionArrays[0][i].getUConst();
3240 resultArray[i].setUConst((value & mask) >> offset);
3241 }
3242 }
3243 }
3244 break;
3245 }
3246 case EOpBitfieldInsert:
3247 {
3248 resultArray = new TConstantUnion[maxObjectSize];
3249 for (size_t i = 0; i < maxObjectSize; ++i)
3250 {
3251 int offset = unionArrays[2][0].getIConst();
3252 int bits = unionArrays[3][0].getIConst();
3253 if (bits == 0)
3254 {
3255 if (aggregate->getBasicType() == EbtInt)
3256 {
3257 int32_t base = unionArrays[0][i].getIConst();
3258 resultArray[i].setIConst(base);
3259 }
3260 else
3261 {
3262 ASSERT(aggregate->getBasicType() == EbtUInt);
3263 uint32_t base = unionArrays[0][i].getUConst();
3264 resultArray[i].setUConst(base);
3265 }
3266 }
3267 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3268 {
3269 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3270 &resultArray[i]);
3271 }
3272 else
3273 {
3274 // bits can be 32 here, so we need to avoid bit shift overflow.
3275 uint32_t maskMsb = 1u << (bits - 1);
3276 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3277 uint32_t baseMask = ~insertMask;
3278 if (aggregate->getBasicType() == EbtInt)
3279 {
3280 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3281 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3282 uint32_t resultUnsigned =
3283 (base & baseMask) | ((insert << offset) & insertMask);
3284 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3285 }
3286 else
3287 {
3288 ASSERT(aggregate->getBasicType() == EbtUInt);
3289 uint32_t base = unionArrays[0][i].getUConst();
3290 uint32_t insert = unionArrays[1][i].getUConst();
3291 resultArray[i].setUConst((base & baseMask) |
3292 ((insert << offset) & insertMask));
3293 }
3294 }
3295 }
3296 break;
3297 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003298
3299 default:
3300 UNREACHABLE();
3301 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303302 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003303 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303304}
3305
3306// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04003307TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
3308{
3309 if (hashFunction == NULL || name.empty())
3310 return name;
3311 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
3312 TStringStream stream;
3313 stream << HASHED_NAME_PREFIX << std::hex << number;
3314 TString hashedName = stream.str();
3315 return hashedName;
3316}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003317
3318void TIntermTraverser::updateTree()
3319{
Olli Etuahoa6f22092015-05-08 18:31:10 +03003320 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
3321 {
3322 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
3323 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003324 if (!insertion.insertionsAfter.empty())
3325 {
3326 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
3327 insertion.insertionsAfter);
3328 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003329 }
3330 if (!insertion.insertionsBefore.empty())
3331 {
3332 bool inserted =
3333 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
3334 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003335 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03003336 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003337 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
3338 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003339 const NodeUpdateEntry &replacement = mReplacements[ii];
3340 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003341 bool replaced =
3342 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003343 ASSERT(replaced);
3344
Olli Etuahocd94ef92015-04-16 19:18:10 +03003345 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003346 {
3347 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03003348 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003349 // be replaced, we need to make sure we don't update the replaced
3350 // node; instead, we update the replacement node.
3351 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
3352 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003353 NodeUpdateEntry &replacement2 = mReplacements[jj];
3354 if (replacement2.parent == replacement.original)
3355 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003356 }
3357 }
3358 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003359 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
3360 {
3361 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
3362 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003363 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
3364 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003365 ASSERT(replaced);
3366 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03003367
Jamie Madill03d863c2016-07-27 18:15:53 -04003368 clearReplacementQueue();
3369}
3370
3371void TIntermTraverser::clearReplacementQueue()
3372{
Olli Etuahod4f303e2015-05-20 17:09:06 +03003373 mReplacements.clear();
3374 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04003375 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003376}
Jamie Madill1048e432016-07-23 18:51:28 -04003377
Jamie Madill03d863c2016-07-27 18:15:53 -04003378void TIntermTraverser::queueReplacement(TIntermNode *original,
3379 TIntermNode *replacement,
3380 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003381{
Jamie Madill03d863c2016-07-27 18:15:53 -04003382 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04003383}
3384
Jamie Madill03d863c2016-07-27 18:15:53 -04003385void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
3386 TIntermNode *original,
3387 TIntermNode *replacement,
3388 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003389{
Jamie Madill03d863c2016-07-27 18:15:53 -04003390 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
3391 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04003392}
Jamie Madill45bcc782016-11-07 13:58:48 -05003393
Olli Etuahofe486322017-03-21 09:30:54 +00003394TName TIntermTraverser::GetInternalFunctionName(const char *name)
3395{
3396 TString nameStr(name);
Olli Etuahofe486322017-03-21 09:30:54 +00003397 TName nameObj(nameStr);
3398 nameObj.setInternal(true);
3399 return nameObj;
3400}
3401
3402TIntermFunctionPrototype *TIntermTraverser::CreateInternalFunctionPrototypeNode(
3403 const TType &returnType,
3404 const char *name,
3405 const TSymbolUniqueId &functionId)
3406{
3407 TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType, functionId);
3408 functionNode->getFunctionSymbolInfo()->setNameObj(GetInternalFunctionName(name));
3409 return functionNode;
3410}
3411
3412TIntermFunctionDefinition *TIntermTraverser::CreateInternalFunctionDefinitionNode(
3413 const TType &returnType,
3414 const char *name,
3415 TIntermBlock *functionBody,
3416 const TSymbolUniqueId &functionId)
3417{
3418 TIntermFunctionPrototype *prototypeNode =
3419 CreateInternalFunctionPrototypeNode(returnType, name, functionId);
3420 return new TIntermFunctionDefinition(prototypeNode, functionBody);
3421}
3422
3423TIntermAggregate *TIntermTraverser::CreateInternalFunctionCallNode(
3424 const TType &returnType,
3425 const char *name,
3426 const TSymbolUniqueId &functionId,
3427 TIntermSequence *arguments)
3428{
3429 TIntermAggregate *functionNode = TIntermAggregate::CreateFunctionCall(
3430 returnType, functionId, GetInternalFunctionName(name), arguments);
3431 return functionNode;
3432}
3433
Jamie Madill45bcc782016-11-07 13:58:48 -05003434} // namespace sh