blob: 3a8fdc026dbe290116f4c722c87bf06b4c425317 [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 Etuaho6d40bbd2016-09-30 13:49:38 +0100453void TIntermBlock::appendStatement(TIntermNode *statement)
454{
Olli Etuaho13389b62016-10-16 11:48:18 +0100455 // Declaration nodes with no children can appear if all the declarators just added constants to
456 // the symbol table instead of generating code. They're no-ops so they aren't added to blocks.
457 if (statement != nullptr && (statement->getAsDeclarationNode() == nullptr ||
458 !statement->getAsDeclarationNode()->getSequence()->empty()))
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100459 {
460 mStatements.push_back(statement);
461 }
462}
463
Olli Etuaho16c745a2017-01-16 17:02:27 +0000464void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
465{
466 ASSERT(parameter != nullptr);
467 mParameters.push_back(parameter);
468}
469
Olli Etuaho13389b62016-10-16 11:48:18 +0100470void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
471{
472 ASSERT(declarator != nullptr);
473 ASSERT(declarator->getAsSymbolNode() != nullptr ||
474 (declarator->getAsBinaryNode() != nullptr &&
475 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
476 ASSERT(mDeclarators.empty() ||
477 declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType()));
478 mDeclarators.push_back(declarator);
479}
480
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300481bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
482{
483 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
484 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
485 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
486 return false;
487}
488
Olli Etuaho57961272016-09-14 13:57:46 +0300489bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400490{
491 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100492 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
493 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400494 return false;
495}
496
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500497bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200498{
499 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100500 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200501 return false;
502}
503
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500504bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200505{
506 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
507 return false;
508}
509
Olli Etuahod7a25242015-08-18 13:49:45 +0300510TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
511{
512 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
513 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
514 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
515 mLine = node.mLine;
516}
517
Olli Etuahod4f4c112016-04-15 15:11:24 +0300518bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
519{
520 TIntermAggregate *constructor = getAsAggregate();
521 if (!constructor || !constructor->isConstructor())
522 {
523 return false;
524 }
525 for (TIntermNode *&node : *constructor->getSequence())
526 {
527 if (!node->getAsConstantUnion())
528 return false;
529 }
530 return true;
531}
532
Corentin Wallez509e4562016-08-25 14:55:44 -0400533// static
534TIntermTyped *TIntermTyped::CreateIndexNode(int index)
535{
536 TConstantUnion *u = new TConstantUnion[1];
537 u[0].setIConst(index);
538
539 TType type(EbtInt, EbpUndefined, EvqConst, 1);
540 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
541 return node;
542}
543
544// static
545TIntermTyped *TIntermTyped::CreateZero(const TType &type)
546{
547 TType constType(type);
548 constType.setQualifier(EvqConst);
549
550 if (!type.isArray() && type.getBasicType() != EbtStruct)
551 {
552 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
553
554 size_t size = constType.getObjectSize();
555 TConstantUnion *u = new TConstantUnion[size];
556 for (size_t i = 0; i < size; ++i)
557 {
558 switch (type.getBasicType())
559 {
560 case EbtFloat:
561 u[i].setFConst(0.0f);
562 break;
563 case EbtInt:
564 u[i].setIConst(0);
565 break;
566 case EbtUInt:
567 u[i].setUConst(0u);
568 break;
569 case EbtBool:
570 u[i].setBConst(false);
571 break;
572 default:
Corentin Wallez17a5c062017-01-22 15:20:53 -0500573 // CreateZero is called by ParseContext that keeps parsing even when an error
574 // occurs, so it is possible for CreateZero to be called with non-basic types.
575 // This happens only on error condition but CreateZero needs to return a value
576 // with the correct type to continue the typecheck. That's why we handle
577 // non-basic type by setting whatever value, we just need the type to be right.
578 u[i].setIConst(42);
579 break;
Corentin Wallez509e4562016-08-25 14:55:44 -0400580 }
581 }
582
583 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
584 return node;
585 }
586
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800587 TIntermSequence *arguments = new TIntermSequence();
Corentin Wallez509e4562016-08-25 14:55:44 -0400588
589 if (type.isArray())
590 {
591 TType elementType(type);
592 elementType.clearArrayness();
593
594 size_t arraySize = type.getArraySize();
595 for (size_t i = 0; i < arraySize; ++i)
596 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800597 arguments->push_back(CreateZero(elementType));
Corentin Wallez509e4562016-08-25 14:55:44 -0400598 }
599 }
600 else
601 {
602 ASSERT(type.getBasicType() == EbtStruct);
603
604 TStructure *structure = type.getStruct();
605 for (const auto &field : structure->fields())
606 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800607 arguments->push_back(CreateZero(*field->type()));
Corentin Wallez509e4562016-08-25 14:55:44 -0400608 }
609 }
610
Olli Etuahofe486322017-03-21 09:30:54 +0000611 return TIntermAggregate::CreateConstructor(constType, sh::TypeToConstructorOperator(type),
612 arguments);
Corentin Wallez509e4562016-08-25 14:55:44 -0400613}
614
Corentin Wallez36fd1002016-12-08 11:30:44 -0500615// static
616TIntermTyped *TIntermTyped::CreateBool(bool value)
617{
618 TConstantUnion *u = new TConstantUnion[1];
619 u[0].setBConst(value);
620
621 TType type(EbtBool, EbpUndefined, EvqConst, 1);
622 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
623 return node;
624}
625
Olli Etuahod7a25242015-08-18 13:49:45 +0300626TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
627{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200628 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300629}
630
Olli Etuahobd674552016-10-06 13:28:42 +0100631void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
632{
633 setName(function.getMangledName());
Olli Etuahofe486322017-03-21 09:30:54 +0000634 setId(TSymbolUniqueId(function));
635}
636
637TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id) : mId(new TSymbolUniqueId(id))
638{
639}
640
641TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
642 : mName(info.mName), mId(nullptr)
643{
644 if (info.mId)
645 {
646 mId = new TSymbolUniqueId(*info.mId);
647 }
648}
649
650TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
651{
652 mName = info.mName;
653 if (info.mId)
654 {
655 mId = new TSymbolUniqueId(*info.mId);
656 }
657 else
658 {
659 mId = nullptr;
660 }
661 return *this;
662}
663
664void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
665{
666 mId = new TSymbolUniqueId(id);
667}
668
669const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
670{
671 ASSERT(mId);
672 return *mId;
Olli Etuahobd674552016-10-06 13:28:42 +0100673}
674
Olli Etuahod7a25242015-08-18 13:49:45 +0300675TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
676 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300677 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100678 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
679 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300680{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800681 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300682 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800683 TIntermTyped *typedArg = arg->getAsTyped();
684 ASSERT(typedArg != nullptr);
685 TIntermTyped *argCopy = typedArg->deepCopy();
686 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300687 }
688}
689
Olli Etuahofe486322017-03-21 09:30:54 +0000690TIntermAggregate *TIntermAggregate::shallowCopy() const
691{
692 TIntermSequence *copySeq = new TIntermSequence();
693 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
694 TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq);
695 *copyNode->getFunctionSymbolInfo() = mFunctionInfo;
696 copyNode->setLine(mLine);
697 return copyNode;
698}
699
Olli Etuahob6fa0432016-09-28 16:28:05 +0100700TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
701{
702 TIntermTyped *operandCopy = node.mOperand->deepCopy();
703 ASSERT(operandCopy != nullptr);
704 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000705 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100706}
707
Olli Etuahod7a25242015-08-18 13:49:45 +0300708TIntermBinary::TIntermBinary(const TIntermBinary &node)
709 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
710{
711 TIntermTyped *leftCopy = node.mLeft->deepCopy();
712 TIntermTyped *rightCopy = node.mRight->deepCopy();
713 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
714 mLeft = leftCopy;
715 mRight = rightCopy;
716}
717
718TIntermUnary::TIntermUnary(const TIntermUnary &node)
719 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
720{
721 TIntermTyped *operandCopy = node.mOperand->deepCopy();
722 ASSERT(operandCopy != nullptr);
723 mOperand = operandCopy;
724}
725
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300726TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300727{
Olli Etuahod7a25242015-08-18 13:49:45 +0300728 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300729 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
730 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300731 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300732 mCondition = conditionCopy;
733 mTrueExpression = trueCopy;
734 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300735}
736
Jamie Madillb1a85f42014-08-19 15:23:24 -0400737bool TIntermOperator::isAssignment() const
738{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300739 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400740}
741
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300742bool TIntermOperator::isMultiplication() const
743{
744 switch (mOp)
745 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500746 case EOpMul:
747 case EOpMatrixTimesMatrix:
748 case EOpMatrixTimesVector:
749 case EOpMatrixTimesScalar:
750 case EOpVectorTimesMatrix:
751 case EOpVectorTimesScalar:
752 return true;
753 default:
754 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300755 }
756}
757
Jamie Madillb1a85f42014-08-19 15:23:24 -0400758//
759// returns true if the operator is for one of the constructors
760//
761bool TIntermOperator::isConstructor() const
762{
763 switch (mOp)
764 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500765 case EOpConstructVec2:
766 case EOpConstructVec3:
767 case EOpConstructVec4:
768 case EOpConstructMat2:
769 case EOpConstructMat2x3:
770 case EOpConstructMat2x4:
771 case EOpConstructMat3x2:
772 case EOpConstructMat3:
773 case EOpConstructMat3x4:
774 case EOpConstructMat4x2:
775 case EOpConstructMat4x3:
776 case EOpConstructMat4:
777 case EOpConstructFloat:
778 case EOpConstructIVec2:
779 case EOpConstructIVec3:
780 case EOpConstructIVec4:
781 case EOpConstructInt:
782 case EOpConstructUVec2:
783 case EOpConstructUVec3:
784 case EOpConstructUVec4:
785 case EOpConstructUInt:
786 case EOpConstructBVec2:
787 case EOpConstructBVec3:
788 case EOpConstructBVec4:
789 case EOpConstructBool:
790 case EOpConstructStruct:
791 return true;
792 default:
793 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400794 }
795}
796
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800797bool TIntermOperator::isFunctionCall() const
798{
799 switch (mOp)
800 {
801 case EOpCallFunctionInAST:
802 case EOpCallBuiltInFunction:
803 case EOpCallInternalRawFunction:
804 return true;
805 default:
806 return false;
807 }
808}
809
Olli Etuaho1dded802016-08-18 18:13:13 +0300810TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
811{
812 if (left.isMatrix())
813 {
814 if (right.isMatrix())
815 {
816 return EOpMatrixTimesMatrix;
817 }
818 else
819 {
820 if (right.isVector())
821 {
822 return EOpMatrixTimesVector;
823 }
824 else
825 {
826 return EOpMatrixTimesScalar;
827 }
828 }
829 }
830 else
831 {
832 if (right.isMatrix())
833 {
834 if (left.isVector())
835 {
836 return EOpVectorTimesMatrix;
837 }
838 else
839 {
840 return EOpMatrixTimesScalar;
841 }
842 }
843 else
844 {
845 // Neither operand is a matrix.
846 if (left.isVector() == right.isVector())
847 {
848 // Leave as component product.
849 return EOpMul;
850 }
851 else
852 {
853 return EOpVectorTimesScalar;
854 }
855 }
856 }
857}
858
859TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
860{
861 if (left.isMatrix())
862 {
863 if (right.isMatrix())
864 {
865 return EOpMatrixTimesMatrixAssign;
866 }
867 else
868 {
869 // right should be scalar, but this may not be validated yet.
870 return EOpMatrixTimesScalarAssign;
871 }
872 }
873 else
874 {
875 if (right.isMatrix())
876 {
877 // Left should be a vector, but this may not be validated yet.
878 return EOpVectorTimesMatrixAssign;
879 }
880 else
881 {
882 // Neither operand is a matrix.
883 if (left.isVector() == right.isVector())
884 {
885 // Leave as component product.
886 return EOpMulAssign;
887 }
888 else
889 {
890 // left should be vector and right should be scalar, but this may not be validated
891 // yet.
892 return EOpVectorTimesScalarAssign;
893 }
894 }
895 }
896}
897
Jamie Madillb1a85f42014-08-19 15:23:24 -0400898//
899// Make sure the type of a unary operator is appropriate for its
900// combination of operation and operand type.
901//
Olli Etuahoa2234302016-08-31 12:05:39 +0300902void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400903{
Olli Etuahoa2234302016-08-31 12:05:39 +0300904 TQualifier resultQualifier = EvqTemporary;
905 if (mOperand->getQualifier() == EvqConst)
906 resultQualifier = EvqConst;
907
908 unsigned char operandPrimarySize =
909 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400910 switch (mOp)
911 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300912 case EOpFloatBitsToInt:
913 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
914 break;
915 case EOpFloatBitsToUint:
916 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
917 break;
918 case EOpIntBitsToFloat:
919 case EOpUintBitsToFloat:
920 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
921 break;
922 case EOpPackSnorm2x16:
923 case EOpPackUnorm2x16:
924 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800925 case EOpPackUnorm4x8:
926 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300927 setType(TType(EbtUInt, EbpHigh, resultQualifier));
928 break;
929 case EOpUnpackSnorm2x16:
930 case EOpUnpackUnorm2x16:
931 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
932 break;
933 case EOpUnpackHalf2x16:
934 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
935 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800936 case EOpUnpackUnorm4x8:
937 case EOpUnpackSnorm4x8:
938 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
939 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300940 case EOpAny:
941 case EOpAll:
942 setType(TType(EbtBool, EbpUndefined, resultQualifier));
943 break;
944 case EOpLength:
945 case EOpDeterminant:
946 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
947 break;
948 case EOpTranspose:
949 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
950 static_cast<unsigned char>(mOperand->getType().getRows()),
951 static_cast<unsigned char>(mOperand->getType().getCols())));
952 break;
953 case EOpIsInf:
954 case EOpIsNan:
955 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
956 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000957 case EOpBitfieldReverse:
958 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
959 break;
960 case EOpBitCount:
961 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
962 break;
963 case EOpFindLSB:
964 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
965 break;
966 case EOpFindMSB:
967 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
968 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300969 default:
970 setType(mOperand->getType());
971 mType.setQualifier(resultQualifier);
972 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400973 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300974}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400975
Olli Etuahob6fa0432016-09-28 16:28:05 +0100976TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
977 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
978 mOperand(operand),
979 mSwizzleOffsets(swizzleOffsets)
980{
981 ASSERT(mSwizzleOffsets.size() <= 4);
982 promote();
983}
984
Olli Etuahoa2234302016-08-31 12:05:39 +0300985TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
986 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
987{
988 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400989}
990
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300991TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
992 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
993{
994 promote();
995}
996
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000997TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
998 : TIntermNode(), mSymbol(symbol)
999{
1000 ASSERT(symbol);
1001 setLine(line);
1002}
1003
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001004TIntermTernary::TIntermTernary(TIntermTyped *cond,
1005 TIntermTyped *trueExpression,
1006 TIntermTyped *falseExpression)
1007 : TIntermTyped(trueExpression->getType()),
1008 mCondition(cond),
1009 mTrueExpression(trueExpression),
1010 mFalseExpression(falseExpression)
1011{
1012 getTypePointer()->setQualifier(
1013 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1014}
1015
1016// static
1017TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1018 TIntermTyped *trueExpression,
1019 TIntermTyped *falseExpression)
1020{
1021 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1022 falseExpression->getQualifier() == EvqConst)
1023 {
1024 return EvqConst;
1025 }
1026 return EvqTemporary;
1027}
1028
Olli Etuahob6fa0432016-09-28 16:28:05 +01001029void TIntermSwizzle::promote()
1030{
1031 TQualifier resultQualifier = EvqTemporary;
1032 if (mOperand->getQualifier() == EvqConst)
1033 resultQualifier = EvqConst;
1034
1035 auto numFields = mSwizzleOffsets.size();
1036 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1037 static_cast<unsigned char>(numFields)));
1038}
1039
1040bool TIntermSwizzle::hasDuplicateOffsets() const
1041{
1042 int offsetCount[4] = {0u, 0u, 0u, 0u};
1043 for (const auto offset : mSwizzleOffsets)
1044 {
1045 offsetCount[offset]++;
1046 if (offsetCount[offset] > 1)
1047 {
1048 return true;
1049 }
1050 }
1051 return false;
1052}
1053
Olli Etuaho09b04a22016-12-15 13:30:26 +00001054bool TIntermSwizzle::offsetsMatch(int offset) const
1055{
1056 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1057}
1058
Olli Etuahob6fa0432016-09-28 16:28:05 +01001059void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1060{
1061 for (const int offset : mSwizzleOffsets)
1062 {
1063 switch (offset)
1064 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001065 case 0:
1066 *out << "x";
1067 break;
1068 case 1:
1069 *out << "y";
1070 break;
1071 case 2:
1072 *out << "z";
1073 break;
1074 case 3:
1075 *out << "w";
1076 break;
1077 default:
1078 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001079 }
1080 }
1081}
1082
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001083TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1084 const TIntermTyped *left,
1085 const TIntermTyped *right)
1086{
1087 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1088 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1089 right->getQualifier() != EvqConst)
1090 {
1091 return EvqTemporary;
1092 }
1093 return EvqConst;
1094}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001095
1096// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001097void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001098{
Olli Etuaho1dded802016-08-18 18:13:13 +03001099 ASSERT(!isMultiplication() ||
1100 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1101
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001102 // Comma is handled as a special case.
1103 if (mOp == EOpComma)
1104 {
1105 setType(mRight->getType());
1106 return;
1107 }
1108
Jamie Madillb1a85f42014-08-19 15:23:24 -04001109 // Base assumption: just make the type the same as the left
1110 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001111 setType(mLeft->getType());
1112
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001113 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001114 // Binary operations results in temporary variables unless both
1115 // operands are const.
1116 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1117 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001118 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001119 getTypePointer()->setQualifier(EvqTemporary);
1120 }
1121
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001122 // Handle indexing ops.
1123 switch (mOp)
1124 {
1125 case EOpIndexDirect:
1126 case EOpIndexIndirect:
1127 if (mLeft->isArray())
1128 {
1129 mType.clearArrayness();
1130 }
1131 else if (mLeft->isMatrix())
1132 {
1133 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1134 static_cast<unsigned char>(mLeft->getRows())));
1135 }
1136 else if (mLeft->isVector())
1137 {
1138 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1139 }
1140 else
1141 {
1142 UNREACHABLE();
1143 }
1144 return;
1145 case EOpIndexDirectStruct:
1146 {
1147 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1148 const int i = mRight->getAsConstantUnion()->getIConst(0);
1149 setType(*fields[i]->type());
1150 getTypePointer()->setQualifier(resultQualifier);
1151 return;
1152 }
1153 case EOpIndexDirectInterfaceBlock:
1154 {
1155 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1156 const int i = mRight->getAsConstantUnion()->getIConst(0);
1157 setType(*fields[i]->type());
1158 getTypePointer()->setQualifier(resultQualifier);
1159 return;
1160 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001161 default:
1162 break;
1163 }
1164
1165 ASSERT(mLeft->isArray() == mRight->isArray());
1166
1167 // The result gets promoted to the highest precision.
1168 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1169 getTypePointer()->setPrecision(higherPrecision);
1170
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001171 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001172
1173 //
1174 // All scalars or structs. Code after this test assumes this case is removed!
1175 //
1176 if (nominalSize == 1)
1177 {
1178 switch (mOp)
1179 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001180 //
1181 // Promote to conditional
1182 //
1183 case EOpEqual:
1184 case EOpNotEqual:
1185 case EOpLessThan:
1186 case EOpGreaterThan:
1187 case EOpLessThanEqual:
1188 case EOpGreaterThanEqual:
1189 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1190 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001191
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001192 //
1193 // And and Or operate on conditionals
1194 //
1195 case EOpLogicalAnd:
1196 case EOpLogicalXor:
1197 case EOpLogicalOr:
1198 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1199 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1200 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001201
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001202 default:
1203 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001204 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001205 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001206 }
1207
1208 // If we reach here, at least one of the operands is vector or matrix.
1209 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001210 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001211
Jamie Madillb1a85f42014-08-19 15:23:24 -04001212 switch (mOp)
1213 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001214 case EOpMul:
1215 break;
1216 case EOpMatrixTimesScalar:
1217 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001218 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001219 setType(TType(basicType, higherPrecision, resultQualifier,
1220 static_cast<unsigned char>(mRight->getCols()),
1221 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001222 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001223 break;
1224 case EOpMatrixTimesVector:
1225 setType(TType(basicType, higherPrecision, resultQualifier,
1226 static_cast<unsigned char>(mLeft->getRows()), 1));
1227 break;
1228 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001229 setType(TType(basicType, higherPrecision, resultQualifier,
1230 static_cast<unsigned char>(mRight->getCols()),
1231 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001232 break;
1233 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001234 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001235 static_cast<unsigned char>(nominalSize), 1));
1236 break;
1237 case EOpVectorTimesMatrix:
1238 setType(TType(basicType, higherPrecision, resultQualifier,
1239 static_cast<unsigned char>(mRight->getCols()), 1));
1240 break;
1241 case EOpMulAssign:
1242 case EOpVectorTimesScalarAssign:
1243 case EOpVectorTimesMatrixAssign:
1244 case EOpMatrixTimesScalarAssign:
1245 case EOpMatrixTimesMatrixAssign:
1246 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1247 break;
1248 case EOpAssign:
1249 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001250 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1251 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1252 break;
1253 case EOpAdd:
1254 case EOpSub:
1255 case EOpDiv:
1256 case EOpIMod:
1257 case EOpBitShiftLeft:
1258 case EOpBitShiftRight:
1259 case EOpBitwiseAnd:
1260 case EOpBitwiseXor:
1261 case EOpBitwiseOr:
1262 case EOpAddAssign:
1263 case EOpSubAssign:
1264 case EOpDivAssign:
1265 case EOpIModAssign:
1266 case EOpBitShiftLeftAssign:
1267 case EOpBitShiftRightAssign:
1268 case EOpBitwiseAndAssign:
1269 case EOpBitwiseXorAssign:
1270 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001271 {
1272 const int secondarySize =
1273 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1274 setType(TType(basicType, higherPrecision, resultQualifier,
1275 static_cast<unsigned char>(nominalSize),
1276 static_cast<unsigned char>(secondarySize)));
1277 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001278 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001279 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001280 case EOpEqual:
1281 case EOpNotEqual:
1282 case EOpLessThan:
1283 case EOpGreaterThan:
1284 case EOpLessThanEqual:
1285 case EOpGreaterThanEqual:
1286 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1287 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001288 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001289 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001290
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001291 case EOpIndexDirect:
1292 case EOpIndexIndirect:
1293 case EOpIndexDirectInterfaceBlock:
1294 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001295 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001296 UNREACHABLE();
1297 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001298 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001299 UNREACHABLE();
1300 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001301 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001302}
1303
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001304const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001305{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001306 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001307 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001308 ASSERT(index < static_cast<int>(getType().getArraySize()));
1309 TType arrayElementType = getType();
1310 arrayElementType.clearArrayness();
1311 size_t arrayElementSize = arrayElementType.getObjectSize();
1312 return &mUnionArrayPointer[arrayElementSize * index];
1313 }
1314 else if (isMatrix())
1315 {
1316 ASSERT(index < getType().getCols());
1317 int size = getType().getRows();
1318 return &mUnionArrayPointer[size * index];
1319 }
1320 else if (isVector())
1321 {
1322 ASSERT(index < getType().getNominalSize());
1323 return &mUnionArrayPointer[index];
1324 }
1325 else
1326 {
1327 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001328 return nullptr;
1329 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001330}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001331
Olli Etuahob6fa0432016-09-28 16:28:05 +01001332TIntermTyped *TIntermSwizzle::fold()
1333{
1334 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1335 if (operandConstant == nullptr)
1336 {
1337 return nullptr;
1338 }
1339
1340 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1341 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1342 {
1343 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1344 }
1345 return CreateFoldedNode(constArray, this, mType.getQualifier());
1346}
1347
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001348TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1349{
1350 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1351 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1352 switch (mOp)
1353 {
1354 case EOpIndexDirect:
1355 {
1356 if (leftConstant == nullptr || rightConstant == nullptr)
1357 {
1358 return nullptr;
1359 }
1360 int index = rightConstant->getIConst(0);
1361
1362 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1363 return CreateFoldedNode(constArray, this, mType.getQualifier());
1364 }
1365 case EOpIndexDirectStruct:
1366 {
1367 if (leftConstant == nullptr || rightConstant == nullptr)
1368 {
1369 return nullptr;
1370 }
1371 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1372 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1373
1374 size_t previousFieldsSize = 0;
1375 for (size_t i = 0; i < index; ++i)
1376 {
1377 previousFieldsSize += fields[i]->type()->getObjectSize();
1378 }
1379
1380 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1381 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1382 }
1383 case EOpIndexIndirect:
1384 case EOpIndexDirectInterfaceBlock:
1385 // Can never be constant folded.
1386 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001387 default:
1388 {
1389 if (leftConstant == nullptr || rightConstant == nullptr)
1390 {
1391 return nullptr;
1392 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001393 TConstantUnion *constArray =
1394 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001395
1396 // Nodes may be constant folded without being qualified as constant.
1397 return CreateFoldedNode(constArray, this, mType.getQualifier());
1398 }
1399 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001400}
1401
Olli Etuahof119a262016-08-19 15:54:22 +03001402TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001403{
1404 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1405 if (operandConstant == nullptr)
1406 {
1407 return nullptr;
1408 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301409
1410 TConstantUnion *constArray = nullptr;
1411 switch (mOp)
1412 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001413 case EOpAny:
1414 case EOpAll:
1415 case EOpLength:
1416 case EOpTranspose:
1417 case EOpDeterminant:
1418 case EOpInverse:
1419 case EOpPackSnorm2x16:
1420 case EOpUnpackSnorm2x16:
1421 case EOpPackUnorm2x16:
1422 case EOpUnpackUnorm2x16:
1423 case EOpPackHalf2x16:
1424 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001425 case EOpPackUnorm4x8:
1426 case EOpPackSnorm4x8:
1427 case EOpUnpackUnorm4x8:
1428 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001429 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1430 break;
1431 default:
1432 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1433 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301434 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001435
1436 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001437 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001438}
1439
Olli Etuahof119a262016-08-19 15:54:22 +03001440TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001441{
1442 // Make sure that all params are constant before actual constant folding.
1443 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001444 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001445 if (param->getAsConstantUnion() == nullptr)
1446 {
1447 return nullptr;
1448 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001449 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001450 TConstantUnion *constArray = nullptr;
1451 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001452 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001453 else
Olli Etuahof119a262016-08-19 15:54:22 +03001454 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001455
1456 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001457 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001458}
1459
Jamie Madillb1a85f42014-08-19 15:23:24 -04001460//
1461// The fold functions see if an operation on a constant can be done in place,
1462// without generating run-time code.
1463//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001464// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001465//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001466TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1467 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001468 TDiagnostics *diagnostics,
1469 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001470{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001471 const TConstantUnion *leftArray = getUnionArrayPointer();
1472 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001473
Olli Etuahof119a262016-08-19 15:54:22 +03001474 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001475
1476 size_t objectSize = getType().getObjectSize();
1477
1478 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1479 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1480 {
1481 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1482 }
1483 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1484 {
1485 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001486 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001487 objectSize = rightNode->getType().getObjectSize();
1488 }
1489
1490 TConstantUnion *resultArray = nullptr;
1491
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001492 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001493 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001494 case EOpAdd:
1495 resultArray = new TConstantUnion[objectSize];
1496 for (size_t i = 0; i < objectSize; i++)
1497 resultArray[i] =
1498 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1499 break;
1500 case EOpSub:
1501 resultArray = new TConstantUnion[objectSize];
1502 for (size_t i = 0; i < objectSize; i++)
1503 resultArray[i] =
1504 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1505 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001506
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001507 case EOpMul:
1508 case EOpVectorTimesScalar:
1509 case EOpMatrixTimesScalar:
1510 resultArray = new TConstantUnion[objectSize];
1511 for (size_t i = 0; i < objectSize; i++)
1512 resultArray[i] =
1513 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1514 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001515
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001516 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001517 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001518 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001519 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001520
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001521 const int leftCols = getCols();
1522 const int leftRows = getRows();
1523 const int rightCols = rightNode->getType().getCols();
1524 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001525 const int resultCols = rightCols;
1526 const int resultRows = leftRows;
1527
1528 resultArray = new TConstantUnion[resultCols * resultRows];
1529 for (int row = 0; row < resultRows; row++)
1530 {
1531 for (int column = 0; column < resultCols; column++)
1532 {
1533 resultArray[resultRows * column + row].setFConst(0.0f);
1534 for (int i = 0; i < leftCols; i++)
1535 {
1536 resultArray[resultRows * column + row].setFConst(
1537 resultArray[resultRows * column + row].getFConst() +
1538 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001539 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001540 }
1541 }
1542 }
1543 }
1544 break;
1545
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001546 case EOpDiv:
1547 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001548 {
1549 resultArray = new TConstantUnion[objectSize];
1550 for (size_t i = 0; i < objectSize; i++)
1551 {
1552 switch (getType().getBasicType())
1553 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001554 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001555 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001556 ASSERT(op == EOpDiv);
1557 float dividend = leftArray[i].getFConst();
1558 float divisor = rightArray[i].getFConst();
1559 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001560 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001561 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001562 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001563 diagnostics->warning(
1564 getLine(),
1565 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001566 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001567 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001568 }
1569 else
1570 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001571 diagnostics->warning(getLine(),
1572 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001573 bool negativeResult =
1574 std::signbit(dividend) != std::signbit(divisor);
1575 resultArray[i].setFConst(
1576 negativeResult ? -std::numeric_limits<float>::infinity()
1577 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001578 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001579 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001580 else if (gl::isInf(dividend) && gl::isInf(divisor))
1581 {
1582 diagnostics->warning(getLine(),
1583 "Infinity divided by infinity during constant "
1584 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001585 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001586 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1587 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001588 else
1589 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001590 float result = dividend / divisor;
1591 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001592 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001593 diagnostics->warning(
1594 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001595 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001596 }
1597 resultArray[i].setFConst(result);
1598 }
1599 break;
1600 }
1601 case EbtInt:
1602 if (rightArray[i] == 0)
1603 {
1604 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001605 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001606 resultArray[i].setIConst(INT_MAX);
1607 }
1608 else
1609 {
1610 int lhs = leftArray[i].getIConst();
1611 int divisor = rightArray[i].getIConst();
1612 if (op == EOpDiv)
1613 {
1614 // Check for the special case where the minimum representable number
1615 // is
1616 // divided by -1. If left alone this leads to integer overflow in
1617 // C++.
1618 // ESSL 3.00.6 section 4.1.3 Integers:
1619 // "However, for the case where the minimum representable value is
1620 // divided by -1, it is allowed to return either the minimum
1621 // representable value or the maximum representable value."
1622 if (lhs == -0x7fffffff - 1 && divisor == -1)
1623 {
1624 resultArray[i].setIConst(0x7fffffff);
1625 }
1626 else
1627 {
1628 resultArray[i].setIConst(lhs / divisor);
1629 }
Olli Etuahod4453572016-09-27 13:21:46 +01001630 }
1631 else
1632 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001633 ASSERT(op == EOpIMod);
1634 if (lhs < 0 || divisor < 0)
1635 {
1636 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1637 // when
1638 // either one of the operands is negative.
1639 diagnostics->warning(getLine(),
1640 "Negative modulus operator operand "
1641 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001642 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001643 resultArray[i].setIConst(0);
1644 }
1645 else
1646 {
1647 resultArray[i].setIConst(lhs % divisor);
1648 }
Olli Etuahod4453572016-09-27 13:21:46 +01001649 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001650 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001651 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001652
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001653 case EbtUInt:
1654 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001655 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001656 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001657 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001658 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001659 }
1660 else
1661 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001662 if (op == EOpDiv)
1663 {
1664 resultArray[i].setUConst(leftArray[i].getUConst() /
1665 rightArray[i].getUConst());
1666 }
1667 else
1668 {
1669 ASSERT(op == EOpIMod);
1670 resultArray[i].setUConst(leftArray[i].getUConst() %
1671 rightArray[i].getUConst());
1672 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001673 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001674 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001675
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001676 default:
1677 UNREACHABLE();
1678 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001679 }
1680 }
1681 }
1682 break;
1683
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001684 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001685 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001686 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001687 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001688
1689 const int matrixCols = getCols();
1690 const int matrixRows = getRows();
1691
1692 resultArray = new TConstantUnion[matrixRows];
1693
1694 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1695 {
1696 resultArray[matrixRow].setFConst(0.0f);
1697 for (int col = 0; col < matrixCols; col++)
1698 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001699 resultArray[matrixRow].setFConst(
1700 resultArray[matrixRow].getFConst() +
1701 leftArray[col * matrixRows + matrixRow].getFConst() *
1702 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001703 }
1704 }
1705 }
1706 break;
1707
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001708 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001709 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001710 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001711 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001712
1713 const int matrixCols = rightNode->getType().getCols();
1714 const int matrixRows = rightNode->getType().getRows();
1715
1716 resultArray = new TConstantUnion[matrixCols];
1717
1718 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1719 {
1720 resultArray[matrixCol].setFConst(0.0f);
1721 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1722 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001723 resultArray[matrixCol].setFConst(
1724 resultArray[matrixCol].getFConst() +
1725 leftArray[matrixRow].getFConst() *
1726 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001727 }
1728 }
1729 }
1730 break;
1731
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001732 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001733 {
1734 resultArray = new TConstantUnion[objectSize];
1735 for (size_t i = 0; i < objectSize; i++)
1736 {
1737 resultArray[i] = leftArray[i] && rightArray[i];
1738 }
1739 }
1740 break;
1741
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001742 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001743 {
1744 resultArray = new TConstantUnion[objectSize];
1745 for (size_t i = 0; i < objectSize; i++)
1746 {
1747 resultArray[i] = leftArray[i] || rightArray[i];
1748 }
1749 }
1750 break;
1751
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001752 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001753 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001754 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001755 resultArray = new TConstantUnion[objectSize];
1756 for (size_t i = 0; i < objectSize; i++)
1757 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001758 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001759 }
1760 }
1761 break;
1762
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001763 case EOpBitwiseAnd:
1764 resultArray = new TConstantUnion[objectSize];
1765 for (size_t i = 0; i < objectSize; i++)
1766 resultArray[i] = leftArray[i] & rightArray[i];
1767 break;
1768 case EOpBitwiseXor:
1769 resultArray = new TConstantUnion[objectSize];
1770 for (size_t i = 0; i < objectSize; i++)
1771 resultArray[i] = leftArray[i] ^ rightArray[i];
1772 break;
1773 case EOpBitwiseOr:
1774 resultArray = new TConstantUnion[objectSize];
1775 for (size_t i = 0; i < objectSize; i++)
1776 resultArray[i] = leftArray[i] | rightArray[i];
1777 break;
1778 case EOpBitShiftLeft:
1779 resultArray = new TConstantUnion[objectSize];
1780 for (size_t i = 0; i < objectSize; i++)
1781 resultArray[i] =
1782 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1783 break;
1784 case EOpBitShiftRight:
1785 resultArray = new TConstantUnion[objectSize];
1786 for (size_t i = 0; i < objectSize; i++)
1787 resultArray[i] =
1788 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1789 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001790
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001791 case EOpLessThan:
1792 ASSERT(objectSize == 1);
1793 resultArray = new TConstantUnion[1];
1794 resultArray->setBConst(*leftArray < *rightArray);
1795 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001796
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001797 case EOpGreaterThan:
1798 ASSERT(objectSize == 1);
1799 resultArray = new TConstantUnion[1];
1800 resultArray->setBConst(*leftArray > *rightArray);
1801 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001802
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001803 case EOpLessThanEqual:
1804 ASSERT(objectSize == 1);
1805 resultArray = new TConstantUnion[1];
1806 resultArray->setBConst(!(*leftArray > *rightArray));
1807 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001808
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001809 case EOpGreaterThanEqual:
1810 ASSERT(objectSize == 1);
1811 resultArray = new TConstantUnion[1];
1812 resultArray->setBConst(!(*leftArray < *rightArray));
1813 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001814
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001815 case EOpEqual:
1816 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001817 {
1818 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001819 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001820 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001821 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001822 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001823 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001824 equal = false;
1825 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001826 }
1827 }
1828 if (op == EOpEqual)
1829 {
1830 resultArray->setBConst(equal);
1831 }
1832 else
1833 {
1834 resultArray->setBConst(!equal);
1835 }
1836 }
1837 break;
1838
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001839 default:
1840 UNREACHABLE();
1841 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001842 }
1843 return resultArray;
1844}
1845
Olli Etuahof119a262016-08-19 15:54:22 +03001846// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1847// code. Returns the constant value to keep using. Nullptr should not be returned.
1848TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001849{
Olli Etuahof119a262016-08-19 15:54:22 +03001850 // Do operations where the return type may have a different number of components compared to the
1851 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001852
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001853 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001854 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301855
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001856 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301857 TConstantUnion *resultArray = nullptr;
1858 switch (op)
1859 {
Olli Etuahof119a262016-08-19 15:54:22 +03001860 case EOpAny:
1861 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301862 resultArray = new TConstantUnion();
1863 resultArray->setBConst(false);
1864 for (size_t i = 0; i < objectSize; i++)
1865 {
1866 if (operandArray[i].getBConst())
1867 {
1868 resultArray->setBConst(true);
1869 break;
1870 }
1871 }
1872 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301873
Olli Etuahof119a262016-08-19 15:54:22 +03001874 case EOpAll:
1875 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301876 resultArray = new TConstantUnion();
1877 resultArray->setBConst(true);
1878 for (size_t i = 0; i < objectSize; i++)
1879 {
1880 if (!operandArray[i].getBConst())
1881 {
1882 resultArray->setBConst(false);
1883 break;
1884 }
1885 }
1886 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301887
Olli Etuahof119a262016-08-19 15:54:22 +03001888 case EOpLength:
1889 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301890 resultArray = new TConstantUnion();
1891 resultArray->setFConst(VectorLength(operandArray, objectSize));
1892 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301893
Olli Etuahof119a262016-08-19 15:54:22 +03001894 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301895 {
Olli Etuahof119a262016-08-19 15:54:22 +03001896 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301897 resultArray = new TConstantUnion[objectSize];
1898 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001899 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301900 SetUnionArrayFromMatrix(result, resultArray);
1901 break;
1902 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301903
Olli Etuahof119a262016-08-19 15:54:22 +03001904 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301905 {
Olli Etuahof119a262016-08-19 15:54:22 +03001906 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301907 unsigned int size = getType().getNominalSize();
1908 ASSERT(size >= 2 && size <= 4);
1909 resultArray = new TConstantUnion();
1910 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1911 break;
1912 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301913
Olli Etuahof119a262016-08-19 15:54:22 +03001914 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301915 {
Olli Etuahof119a262016-08-19 15:54:22 +03001916 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301917 unsigned int size = getType().getNominalSize();
1918 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001919 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301920 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1921 SetUnionArrayFromMatrix(result, resultArray);
1922 break;
1923 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301924
Olli Etuahof119a262016-08-19 15:54:22 +03001925 case EOpPackSnorm2x16:
1926 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301927 ASSERT(getType().getNominalSize() == 2);
1928 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001929 resultArray->setUConst(
1930 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301931 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301932
Olli Etuahof119a262016-08-19 15:54:22 +03001933 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301934 {
Olli Etuahof119a262016-08-19 15:54:22 +03001935 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301936 resultArray = new TConstantUnion[2];
1937 float f1, f2;
1938 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1939 resultArray[0].setFConst(f1);
1940 resultArray[1].setFConst(f2);
1941 break;
1942 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301943
Olli Etuahof119a262016-08-19 15:54:22 +03001944 case EOpPackUnorm2x16:
1945 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301946 ASSERT(getType().getNominalSize() == 2);
1947 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001948 resultArray->setUConst(
1949 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301950 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301951
Olli Etuahof119a262016-08-19 15:54:22 +03001952 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301953 {
Olli Etuahof119a262016-08-19 15:54:22 +03001954 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301955 resultArray = new TConstantUnion[2];
1956 float f1, f2;
1957 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1958 resultArray[0].setFConst(f1);
1959 resultArray[1].setFConst(f2);
1960 break;
1961 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301962
Olli Etuahof119a262016-08-19 15:54:22 +03001963 case EOpPackHalf2x16:
1964 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301965 ASSERT(getType().getNominalSize() == 2);
1966 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001967 resultArray->setUConst(
1968 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301969 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301970
Olli Etuahof119a262016-08-19 15:54:22 +03001971 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301972 {
Olli Etuahof119a262016-08-19 15:54:22 +03001973 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301974 resultArray = new TConstantUnion[2];
1975 float f1, f2;
1976 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1977 resultArray[0].setFConst(f1);
1978 resultArray[1].setFConst(f2);
1979 break;
1980 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301981
Olli Etuaho25aef452017-01-29 16:15:44 -08001982 case EOpPackUnorm4x8:
1983 {
1984 ASSERT(getType().getBasicType() == EbtFloat);
1985 resultArray = new TConstantUnion();
1986 resultArray->setUConst(
1987 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1988 operandArray[2].getFConst(), operandArray[3].getFConst()));
1989 break;
1990 }
1991 case EOpPackSnorm4x8:
1992 {
1993 ASSERT(getType().getBasicType() == EbtFloat);
1994 resultArray = new TConstantUnion();
1995 resultArray->setUConst(
1996 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1997 operandArray[2].getFConst(), operandArray[3].getFConst()));
1998 break;
1999 }
2000 case EOpUnpackUnorm4x8:
2001 {
2002 ASSERT(getType().getBasicType() == EbtUInt);
2003 resultArray = new TConstantUnion[4];
2004 float f[4];
2005 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2006 for (size_t i = 0; i < 4; ++i)
2007 {
2008 resultArray[i].setFConst(f[i]);
2009 }
2010 break;
2011 }
2012 case EOpUnpackSnorm4x8:
2013 {
2014 ASSERT(getType().getBasicType() == EbtUInt);
2015 resultArray = new TConstantUnion[4];
2016 float f[4];
2017 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2018 for (size_t i = 0; i < 4; ++i)
2019 {
2020 resultArray[i].setFConst(f[i]);
2021 }
2022 break;
2023 }
2024
Olli Etuahof119a262016-08-19 15:54:22 +03002025 default:
2026 UNREACHABLE();
2027 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302028 }
2029
2030 return resultArray;
2031}
2032
Olli Etuahof119a262016-08-19 15:54:22 +03002033TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2034 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302035{
Olli Etuahof119a262016-08-19 15:54:22 +03002036 // Do unary operations where each component of the result is computed based on the corresponding
2037 // component of the operand. Also folds normalize, though the divisor in that case takes all
2038 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302039
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002040 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002041 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002042
2043 size_t objectSize = getType().getObjectSize();
2044
Arun Patoleab2b9a22015-07-06 18:27:56 +05302045 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2046 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302047 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002048 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302049 {
Olli Etuahof119a262016-08-19 15:54:22 +03002050 case EOpNegative:
2051 switch (getType().getBasicType())
2052 {
2053 case EbtFloat:
2054 resultArray[i].setFConst(-operandArray[i].getFConst());
2055 break;
2056 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002057 if (operandArray[i] == std::numeric_limits<int>::min())
2058 {
2059 // The minimum representable integer doesn't have a positive
2060 // counterpart, rather the negation overflows and in ESSL is supposed to
2061 // wrap back to the minimum representable integer. Make sure that we
2062 // don't actually let the negation overflow, which has undefined
2063 // behavior in C++.
2064 resultArray[i].setIConst(std::numeric_limits<int>::min());
2065 }
2066 else
2067 {
2068 resultArray[i].setIConst(-operandArray[i].getIConst());
2069 }
Olli Etuahof119a262016-08-19 15:54:22 +03002070 break;
2071 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002072 if (operandArray[i] == 0x80000000u)
2073 {
2074 resultArray[i].setUConst(0x80000000u);
2075 }
2076 else
2077 {
2078 resultArray[i].setUConst(static_cast<unsigned int>(
2079 -static_cast<int>(operandArray[i].getUConst())));
2080 }
Olli Etuahof119a262016-08-19 15:54:22 +03002081 break;
2082 default:
2083 UNREACHABLE();
2084 return nullptr;
2085 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302086 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302087
Olli Etuahof119a262016-08-19 15:54:22 +03002088 case EOpPositive:
2089 switch (getType().getBasicType())
2090 {
2091 case EbtFloat:
2092 resultArray[i].setFConst(operandArray[i].getFConst());
2093 break;
2094 case EbtInt:
2095 resultArray[i].setIConst(operandArray[i].getIConst());
2096 break;
2097 case EbtUInt:
2098 resultArray[i].setUConst(static_cast<unsigned int>(
2099 static_cast<int>(operandArray[i].getUConst())));
2100 break;
2101 default:
2102 UNREACHABLE();
2103 return nullptr;
2104 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302105 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302106
Olli Etuahof119a262016-08-19 15:54:22 +03002107 case EOpLogicalNot:
2108 switch (getType().getBasicType())
2109 {
2110 case EbtBool:
2111 resultArray[i].setBConst(!operandArray[i].getBConst());
2112 break;
2113 default:
2114 UNREACHABLE();
2115 return nullptr;
2116 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302117 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302118
Olli Etuahof119a262016-08-19 15:54:22 +03002119 case EOpBitwiseNot:
2120 switch (getType().getBasicType())
2121 {
2122 case EbtInt:
2123 resultArray[i].setIConst(~operandArray[i].getIConst());
2124 break;
2125 case EbtUInt:
2126 resultArray[i].setUConst(~operandArray[i].getUConst());
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 EOpRadians:
2135 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2137 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302138
Olli Etuahof119a262016-08-19 15:54:22 +03002139 case EOpDegrees:
2140 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302141 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2142 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302143
Olli Etuahof119a262016-08-19 15:54:22 +03002144 case EOpSin:
2145 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302146 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302147
Olli Etuahof119a262016-08-19 15:54:22 +03002148 case EOpCos:
2149 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2150 break;
2151
2152 case EOpTan:
2153 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2154 break;
2155
2156 case EOpAsin:
2157 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2158 // 0.
2159 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2160 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2161 diagnostics, &resultArray[i]);
2162 else
2163 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2164 break;
2165
2166 case EOpAcos:
2167 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2168 // 0.
2169 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2170 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2171 diagnostics, &resultArray[i]);
2172 else
2173 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2174 break;
2175
2176 case EOpAtan:
2177 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2178 break;
2179
2180 case EOpSinh:
2181 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2182 break;
2183
2184 case EOpCosh:
2185 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2186 break;
2187
2188 case EOpTanh:
2189 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2190 break;
2191
2192 case EOpAsinh:
2193 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2194 break;
2195
2196 case EOpAcosh:
2197 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2198 if (operandArray[i].getFConst() < 1.0f)
2199 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2200 diagnostics, &resultArray[i]);
2201 else
2202 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2203 break;
2204
2205 case EOpAtanh:
2206 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2207 // 0.
2208 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2209 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2210 diagnostics, &resultArray[i]);
2211 else
2212 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2213 break;
2214
2215 case EOpAbs:
2216 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302217 {
Olli Etuahof119a262016-08-19 15:54:22 +03002218 case EbtFloat:
2219 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2220 break;
2221 case EbtInt:
2222 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2223 break;
2224 default:
2225 UNREACHABLE();
2226 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302227 }
2228 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002229
2230 case EOpSign:
2231 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302232 {
Olli Etuahof119a262016-08-19 15:54:22 +03002233 case EbtFloat:
2234 {
2235 float fConst = operandArray[i].getFConst();
2236 float fResult = 0.0f;
2237 if (fConst > 0.0f)
2238 fResult = 1.0f;
2239 else if (fConst < 0.0f)
2240 fResult = -1.0f;
2241 resultArray[i].setFConst(fResult);
2242 break;
2243 }
2244 case EbtInt:
2245 {
2246 int iConst = operandArray[i].getIConst();
2247 int iResult = 0;
2248 if (iConst > 0)
2249 iResult = 1;
2250 else if (iConst < 0)
2251 iResult = -1;
2252 resultArray[i].setIConst(iResult);
2253 break;
2254 }
2255 default:
2256 UNREACHABLE();
2257 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302258 }
2259 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302260
Olli Etuahof119a262016-08-19 15:54:22 +03002261 case EOpFloor:
2262 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2263 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302264
Olli Etuahof119a262016-08-19 15:54:22 +03002265 case EOpTrunc:
2266 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2267 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302268
Olli Etuahof119a262016-08-19 15:54:22 +03002269 case EOpRound:
2270 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2271 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302272
Olli Etuahof119a262016-08-19 15:54:22 +03002273 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302274 {
Olli Etuahof119a262016-08-19 15:54:22 +03002275 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302276 float x = operandArray[i].getFConst();
2277 float result;
2278 float fractPart = modff(x, &result);
2279 if (fabsf(fractPart) == 0.5f)
2280 result = 2.0f * roundf(x / 2.0f);
2281 else
2282 result = roundf(x);
2283 resultArray[i].setFConst(result);
2284 break;
2285 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302286
Olli Etuahof119a262016-08-19 15:54:22 +03002287 case EOpCeil:
2288 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2289 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302290
Olli Etuahof119a262016-08-19 15:54:22 +03002291 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302292 {
Olli Etuahof119a262016-08-19 15:54:22 +03002293 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302294 float x = operandArray[i].getFConst();
2295 resultArray[i].setFConst(x - floorf(x));
2296 break;
2297 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302298
Olli Etuahof119a262016-08-19 15:54:22 +03002299 case EOpIsNan:
2300 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302301 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2302 break;
Arun Patole551279e2015-07-07 18:18:23 +05302303
Olli Etuahof119a262016-08-19 15:54:22 +03002304 case EOpIsInf:
2305 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302306 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2307 break;
Arun Patole551279e2015-07-07 18:18:23 +05302308
Olli Etuahof119a262016-08-19 15:54:22 +03002309 case EOpFloatBitsToInt:
2310 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302311 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2312 break;
Arun Patole551279e2015-07-07 18:18:23 +05302313
Olli Etuahof119a262016-08-19 15:54:22 +03002314 case EOpFloatBitsToUint:
2315 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302316 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2317 break;
Arun Patole551279e2015-07-07 18:18:23 +05302318
Olli Etuahof119a262016-08-19 15:54:22 +03002319 case EOpIntBitsToFloat:
2320 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302321 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2322 break;
Arun Patole551279e2015-07-07 18:18:23 +05302323
Olli Etuahof119a262016-08-19 15:54:22 +03002324 case EOpUintBitsToFloat:
2325 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302326 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2327 break;
Arun Patole551279e2015-07-07 18:18:23 +05302328
Olli Etuahof119a262016-08-19 15:54:22 +03002329 case EOpExp:
2330 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2331 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302332
Olli Etuahof119a262016-08-19 15:54:22 +03002333 case EOpLog:
2334 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2335 if (operandArray[i].getFConst() <= 0.0f)
2336 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2337 diagnostics, &resultArray[i]);
2338 else
2339 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2340 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302341
Olli Etuahof119a262016-08-19 15:54:22 +03002342 case EOpExp2:
2343 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2344 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302345
Olli Etuahof119a262016-08-19 15:54:22 +03002346 case EOpLog2:
2347 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2348 // And log2f is not available on some plarforms like old android, so just using
2349 // log(x)/log(2) here.
2350 if (operandArray[i].getFConst() <= 0.0f)
2351 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2352 diagnostics, &resultArray[i]);
2353 else
2354 {
2355 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2356 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2357 }
2358 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302359
Olli Etuahof119a262016-08-19 15:54:22 +03002360 case EOpSqrt:
2361 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2362 if (operandArray[i].getFConst() < 0.0f)
2363 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2364 diagnostics, &resultArray[i]);
2365 else
2366 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2367 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302368
Olli Etuahof119a262016-08-19 15:54:22 +03002369 case EOpInverseSqrt:
2370 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2371 // so getting the square root first using builtin function sqrt() and then taking
2372 // its inverse.
2373 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2374 // result to 0.
2375 if (operandArray[i].getFConst() <= 0.0f)
2376 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2377 diagnostics, &resultArray[i]);
2378 else
2379 {
2380 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2381 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2382 }
2383 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302384
Olli Etuahod68924e2017-01-02 17:34:40 +00002385 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002386 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302387 resultArray[i].setBConst(!operandArray[i].getBConst());
2388 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302389
Olli Etuahof119a262016-08-19 15:54:22 +03002390 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302391 {
Olli Etuahof119a262016-08-19 15:54:22 +03002392 ASSERT(getType().getBasicType() == EbtFloat);
2393 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302394 float length = VectorLength(operandArray, objectSize);
2395 if (length)
2396 resultArray[i].setFConst(x / length);
2397 else
Olli Etuahof119a262016-08-19 15:54:22 +03002398 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2399 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302400 break;
2401 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002402 case EOpBitfieldReverse:
2403 {
2404 uint32_t value;
2405 if (getType().getBasicType() == EbtInt)
2406 {
2407 value = static_cast<uint32_t>(operandArray[i].getIConst());
2408 }
2409 else
2410 {
2411 ASSERT(getType().getBasicType() == EbtUInt);
2412 value = operandArray[i].getUConst();
2413 }
2414 uint32_t result = gl::BitfieldReverse(value);
2415 if (getType().getBasicType() == EbtInt)
2416 {
2417 resultArray[i].setIConst(static_cast<int32_t>(result));
2418 }
2419 else
2420 {
2421 resultArray[i].setUConst(result);
2422 }
2423 break;
2424 }
2425 case EOpBitCount:
2426 {
2427 uint32_t value;
2428 if (getType().getBasicType() == EbtInt)
2429 {
2430 value = static_cast<uint32_t>(operandArray[i].getIConst());
2431 }
2432 else
2433 {
2434 ASSERT(getType().getBasicType() == EbtUInt);
2435 value = operandArray[i].getUConst();
2436 }
2437 int result = gl::BitCount(value);
2438 resultArray[i].setIConst(result);
2439 break;
2440 }
2441 case EOpFindLSB:
2442 {
2443 uint32_t value;
2444 if (getType().getBasicType() == EbtInt)
2445 {
2446 value = static_cast<uint32_t>(operandArray[i].getIConst());
2447 }
2448 else
2449 {
2450 ASSERT(getType().getBasicType() == EbtUInt);
2451 value = operandArray[i].getUConst();
2452 }
2453 resultArray[i].setIConst(gl::FindLSB(value));
2454 break;
2455 }
2456 case EOpFindMSB:
2457 {
2458 uint32_t value;
2459 if (getType().getBasicType() == EbtInt)
2460 {
2461 int intValue = operandArray[i].getIConst();
2462 value = static_cast<uint32_t>(intValue);
2463 if (intValue < 0)
2464 {
2465 // Look for zero instead of one in value. This also handles the intValue ==
2466 // -1 special case, where the return value needs to be -1.
2467 value = ~value;
2468 }
2469 }
2470 else
2471 {
2472 ASSERT(getType().getBasicType() == EbtUInt);
2473 value = operandArray[i].getUConst();
2474 }
2475 resultArray[i].setIConst(gl::FindMSB(value));
2476 break;
2477 }
Olli Etuahof119a262016-08-19 15:54:22 +03002478 case EOpDFdx:
2479 case EOpDFdy:
2480 case EOpFwidth:
2481 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302482 // Derivatives of constant arguments should be 0.
2483 resultArray[i].setFConst(0.0f);
2484 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302485
Olli Etuahof119a262016-08-19 15:54:22 +03002486 default:
2487 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302488 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302489 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002490
Arun Patoleab2b9a22015-07-06 18:27:56 +05302491 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002492}
2493
Olli Etuahof119a262016-08-19 15:54:22 +03002494void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2495 FloatTypeUnaryFunc builtinFunc,
2496 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302497{
2498 ASSERT(builtinFunc);
2499
Olli Etuahof119a262016-08-19 15:54:22 +03002500 ASSERT(getType().getBasicType() == EbtFloat);
2501 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302502}
2503
Jamie Madillb1a85f42014-08-19 15:23:24 -04002504// static
Olli Etuahof119a262016-08-19 15:54:22 +03002505TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002506{
2507 ASSERT(aggregate->getSequence()->size() > 0u);
2508 size_t resultSize = aggregate->getType().getObjectSize();
2509 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2510 TBasicType basicType = aggregate->getBasicType();
2511
2512 size_t resultIndex = 0u;
2513
2514 if (aggregate->getSequence()->size() == 1u)
2515 {
2516 TIntermNode *argument = aggregate->getSequence()->front();
2517 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2518 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2519 // Check the special case of constructing a matrix diagonal from a single scalar,
2520 // or a vector from a single scalar.
2521 if (argumentConstant->getType().getObjectSize() == 1u)
2522 {
2523 if (aggregate->isMatrix())
2524 {
2525 int resultCols = aggregate->getType().getCols();
2526 int resultRows = aggregate->getType().getRows();
2527 for (int col = 0; col < resultCols; ++col)
2528 {
2529 for (int row = 0; row < resultRows; ++row)
2530 {
2531 if (col == row)
2532 {
2533 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2534 }
2535 else
2536 {
2537 resultArray[resultIndex].setFConst(0.0f);
2538 }
2539 ++resultIndex;
2540 }
2541 }
2542 }
2543 else
2544 {
2545 while (resultIndex < resultSize)
2546 {
2547 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2548 ++resultIndex;
2549 }
2550 }
2551 ASSERT(resultIndex == resultSize);
2552 return resultArray;
2553 }
2554 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2555 {
2556 // The special case of constructing a matrix from a matrix.
2557 int argumentCols = argumentConstant->getType().getCols();
2558 int argumentRows = argumentConstant->getType().getRows();
2559 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002560 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002561 for (int col = 0; col < resultCols; ++col)
2562 {
2563 for (int row = 0; row < resultRows; ++row)
2564 {
2565 if (col < argumentCols && row < argumentRows)
2566 {
2567 resultArray[resultIndex].cast(basicType,
2568 argumentUnionArray[col * argumentRows + row]);
2569 }
2570 else if (col == row)
2571 {
2572 resultArray[resultIndex].setFConst(1.0f);
2573 }
2574 else
2575 {
2576 resultArray[resultIndex].setFConst(0.0f);
2577 }
2578 ++resultIndex;
2579 }
2580 }
2581 ASSERT(resultIndex == resultSize);
2582 return resultArray;
2583 }
2584 }
2585
2586 for (TIntermNode *&argument : *aggregate->getSequence())
2587 {
2588 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2589 size_t argumentSize = argumentConstant->getType().getObjectSize();
2590 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2591 for (size_t i = 0u; i < argumentSize; ++i)
2592 {
2593 if (resultIndex >= resultSize)
2594 break;
2595 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2596 ++resultIndex;
2597 }
2598 }
2599 ASSERT(resultIndex == resultSize);
2600 return resultArray;
2601}
2602
2603// static
Olli Etuahof119a262016-08-19 15:54:22 +03002604TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2605 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302606{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002607 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002608 TIntermSequence *arguments = aggregate->getSequence();
2609 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2610 std::vector<const TConstantUnion *> unionArrays(argsCount);
2611 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002612 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302613 TBasicType basicType = EbtVoid;
2614 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002615 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302616 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002617 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2618 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302619
2620 if (i == 0)
2621 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002622 basicType = argConstant->getType().getBasicType();
2623 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302624 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002625 unionArrays[i] = argConstant->getUnionArrayPointer();
2626 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002627 if (objectSizes[i] > maxObjectSize)
2628 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302629 }
2630
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002631 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302632 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002633 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302634 if (objectSizes[i] != maxObjectSize)
2635 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2636 }
Arun Patole274f0702015-05-05 13:33:30 +05302637
Olli Etuahob43846e2015-06-02 18:18:57 +03002638 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002639
2640 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302641 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002642 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302643 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002644 ASSERT(basicType == EbtFloat);
2645 resultArray = new TConstantUnion[maxObjectSize];
2646 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302647 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002648 float y = unionArrays[0][i].getFConst();
2649 float x = unionArrays[1][i].getFConst();
2650 // Results are undefined if x and y are both 0.
2651 if (x == 0.0f && y == 0.0f)
2652 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2653 else
2654 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302655 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002656 break;
2657 }
Arun Patolebf790422015-05-18 17:53:04 +05302658
Olli Etuaho51182ab2017-01-22 00:12:29 +00002659 case EOpPow:
2660 {
2661 ASSERT(basicType == EbtFloat);
2662 resultArray = new TConstantUnion[maxObjectSize];
2663 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302664 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002665 float x = unionArrays[0][i].getFConst();
2666 float y = unionArrays[1][i].getFConst();
2667 // Results are undefined if x < 0.
2668 // Results are undefined if x = 0 and y <= 0.
2669 if (x < 0.0f)
2670 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2671 else if (x == 0.0f && y <= 0.0f)
2672 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2673 else
2674 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302675 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002676 break;
2677 }
Arun Patolebf790422015-05-18 17:53:04 +05302678
Olli Etuaho51182ab2017-01-22 00:12:29 +00002679 case EOpMod:
2680 {
2681 ASSERT(basicType == EbtFloat);
2682 resultArray = new TConstantUnion[maxObjectSize];
2683 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302684 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002685 float x = unionArrays[0][i].getFConst();
2686 float y = unionArrays[1][i].getFConst();
2687 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302688 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002689 break;
2690 }
Arun Patolebf790422015-05-18 17:53:04 +05302691
Olli Etuaho51182ab2017-01-22 00:12:29 +00002692 case EOpMin:
2693 {
2694 resultArray = new TConstantUnion[maxObjectSize];
2695 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302696 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002697 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302698 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002699 case EbtFloat:
2700 resultArray[i].setFConst(
2701 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2702 break;
2703 case EbtInt:
2704 resultArray[i].setIConst(
2705 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2706 break;
2707 case EbtUInt:
2708 resultArray[i].setUConst(
2709 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2710 break;
2711 default:
2712 UNREACHABLE();
2713 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302714 }
2715 }
2716 break;
Arun Patole274f0702015-05-05 13:33:30 +05302717 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002718
2719 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302720 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002721 resultArray = new TConstantUnion[maxObjectSize];
2722 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302723 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002724 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302725 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002726 case EbtFloat:
2727 resultArray[i].setFConst(
2728 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2729 break;
2730 case EbtInt:
2731 resultArray[i].setIConst(
2732 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2733 break;
2734 case EbtUInt:
2735 resultArray[i].setUConst(
2736 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2737 break;
2738 default:
2739 UNREACHABLE();
2740 break;
Arun Patole274f0702015-05-05 13:33:30 +05302741 }
2742 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002743 break;
Arun Patole274f0702015-05-05 13:33:30 +05302744 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002745
2746 case EOpStep:
2747 {
2748 ASSERT(basicType == EbtFloat);
2749 resultArray = new TConstantUnion[maxObjectSize];
2750 for (size_t i = 0; i < maxObjectSize; i++)
2751 resultArray[i].setFConst(
2752 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2753 break;
2754 }
2755
2756 case EOpLessThanComponentWise:
2757 {
2758 resultArray = new TConstantUnion[maxObjectSize];
2759 for (size_t i = 0; i < maxObjectSize; i++)
2760 {
2761 switch (basicType)
2762 {
2763 case EbtFloat:
2764 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2765 unionArrays[1][i].getFConst());
2766 break;
2767 case EbtInt:
2768 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2769 unionArrays[1][i].getIConst());
2770 break;
2771 case EbtUInt:
2772 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2773 unionArrays[1][i].getUConst());
2774 break;
2775 default:
2776 UNREACHABLE();
2777 break;
2778 }
2779 }
2780 break;
2781 }
2782
2783 case EOpLessThanEqualComponentWise:
2784 {
2785 resultArray = new TConstantUnion[maxObjectSize];
2786 for (size_t i = 0; i < maxObjectSize; i++)
2787 {
2788 switch (basicType)
2789 {
2790 case EbtFloat:
2791 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2792 unionArrays[1][i].getFConst());
2793 break;
2794 case EbtInt:
2795 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2796 unionArrays[1][i].getIConst());
2797 break;
2798 case EbtUInt:
2799 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2800 unionArrays[1][i].getUConst());
2801 break;
2802 default:
2803 UNREACHABLE();
2804 break;
2805 }
2806 }
2807 break;
2808 }
2809
2810 case EOpGreaterThanComponentWise:
2811 {
2812 resultArray = new TConstantUnion[maxObjectSize];
2813 for (size_t i = 0; i < maxObjectSize; i++)
2814 {
2815 switch (basicType)
2816 {
2817 case EbtFloat:
2818 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2819 unionArrays[1][i].getFConst());
2820 break;
2821 case EbtInt:
2822 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2823 unionArrays[1][i].getIConst());
2824 break;
2825 case EbtUInt:
2826 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2827 unionArrays[1][i].getUConst());
2828 break;
2829 default:
2830 UNREACHABLE();
2831 break;
2832 }
2833 }
2834 break;
2835 }
2836 case EOpGreaterThanEqualComponentWise:
2837 {
2838 resultArray = new TConstantUnion[maxObjectSize];
2839 for (size_t i = 0; i < maxObjectSize; i++)
2840 {
2841 switch (basicType)
2842 {
2843 case EbtFloat:
2844 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2845 unionArrays[1][i].getFConst());
2846 break;
2847 case EbtInt:
2848 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2849 unionArrays[1][i].getIConst());
2850 break;
2851 case EbtUInt:
2852 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2853 unionArrays[1][i].getUConst());
2854 break;
2855 default:
2856 UNREACHABLE();
2857 break;
2858 }
2859 }
2860 }
2861 break;
2862
2863 case EOpEqualComponentWise:
2864 {
2865 resultArray = new TConstantUnion[maxObjectSize];
2866 for (size_t i = 0; i < maxObjectSize; i++)
2867 {
2868 switch (basicType)
2869 {
2870 case EbtFloat:
2871 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2872 unionArrays[1][i].getFConst());
2873 break;
2874 case EbtInt:
2875 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2876 unionArrays[1][i].getIConst());
2877 break;
2878 case EbtUInt:
2879 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2880 unionArrays[1][i].getUConst());
2881 break;
2882 case EbtBool:
2883 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2884 unionArrays[1][i].getBConst());
2885 break;
2886 default:
2887 UNREACHABLE();
2888 break;
2889 }
2890 }
2891 break;
2892 }
2893
2894 case EOpNotEqualComponentWise:
2895 {
2896 resultArray = new TConstantUnion[maxObjectSize];
2897 for (size_t i = 0; i < maxObjectSize; i++)
2898 {
2899 switch (basicType)
2900 {
2901 case EbtFloat:
2902 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2903 unionArrays[1][i].getFConst());
2904 break;
2905 case EbtInt:
2906 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2907 unionArrays[1][i].getIConst());
2908 break;
2909 case EbtUInt:
2910 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2911 unionArrays[1][i].getUConst());
2912 break;
2913 case EbtBool:
2914 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2915 unionArrays[1][i].getBConst());
2916 break;
2917 default:
2918 UNREACHABLE();
2919 break;
2920 }
2921 }
2922 break;
2923 }
2924
2925 case EOpDistance:
2926 {
2927 ASSERT(basicType == EbtFloat);
2928 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2929 resultArray = new TConstantUnion();
2930 for (size_t i = 0; i < maxObjectSize; i++)
2931 {
2932 float x = unionArrays[0][i].getFConst();
2933 float y = unionArrays[1][i].getFConst();
2934 distanceArray[i].setFConst(x - y);
2935 }
2936 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2937 break;
2938 }
2939
2940 case EOpDot:
2941 ASSERT(basicType == EbtFloat);
2942 resultArray = new TConstantUnion();
2943 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2944 break;
2945
2946 case EOpCross:
2947 {
2948 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2949 resultArray = new TConstantUnion[maxObjectSize];
2950 float x0 = unionArrays[0][0].getFConst();
2951 float x1 = unionArrays[0][1].getFConst();
2952 float x2 = unionArrays[0][2].getFConst();
2953 float y0 = unionArrays[1][0].getFConst();
2954 float y1 = unionArrays[1][1].getFConst();
2955 float y2 = unionArrays[1][2].getFConst();
2956 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2957 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2958 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2959 break;
2960 }
2961
2962 case EOpReflect:
2963 {
2964 ASSERT(basicType == EbtFloat);
2965 // genType reflect (genType I, genType N) :
2966 // For the incident vector I and surface orientation N, returns the reflection
2967 // direction:
2968 // I - 2 * dot(N, I) * N.
2969 resultArray = new TConstantUnion[maxObjectSize];
2970 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2971 for (size_t i = 0; i < maxObjectSize; i++)
2972 {
2973 float result = unionArrays[0][i].getFConst() -
2974 2.0f * dotProduct * unionArrays[1][i].getFConst();
2975 resultArray[i].setFConst(result);
2976 }
2977 break;
2978 }
2979
2980 case EOpMulMatrixComponentWise:
2981 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002982 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
2983 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00002984 // Perform component-wise matrix multiplication.
2985 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002986 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002987 angle::Matrix<float> result =
2988 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2989 SetUnionArrayFromMatrix(result, resultArray);
2990 break;
2991 }
2992
2993 case EOpOuterProduct:
2994 {
2995 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002996 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
2997 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002998 resultArray = new TConstantUnion[numRows * numCols];
2999 angle::Matrix<float> result =
3000 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3001 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3002 SetUnionArrayFromMatrix(result, resultArray);
3003 break;
3004 }
3005
3006 case EOpClamp:
3007 {
3008 resultArray = new TConstantUnion[maxObjectSize];
3009 for (size_t i = 0; i < maxObjectSize; i++)
3010 {
3011 switch (basicType)
3012 {
3013 case EbtFloat:
3014 {
3015 float x = unionArrays[0][i].getFConst();
3016 float min = unionArrays[1][i].getFConst();
3017 float max = unionArrays[2][i].getFConst();
3018 // Results are undefined if min > max.
3019 if (min > max)
3020 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3021 &resultArray[i]);
3022 else
3023 resultArray[i].setFConst(gl::clamp(x, min, max));
3024 break;
3025 }
3026
3027 case EbtInt:
3028 {
3029 int x = unionArrays[0][i].getIConst();
3030 int min = unionArrays[1][i].getIConst();
3031 int max = unionArrays[2][i].getIConst();
3032 // Results are undefined if min > max.
3033 if (min > max)
3034 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3035 &resultArray[i]);
3036 else
3037 resultArray[i].setIConst(gl::clamp(x, min, max));
3038 break;
3039 }
3040 case EbtUInt:
3041 {
3042 unsigned int x = unionArrays[0][i].getUConst();
3043 unsigned int min = unionArrays[1][i].getUConst();
3044 unsigned int max = unionArrays[2][i].getUConst();
3045 // Results are undefined if min > max.
3046 if (min > max)
3047 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3048 &resultArray[i]);
3049 else
3050 resultArray[i].setUConst(gl::clamp(x, min, max));
3051 break;
3052 }
3053 default:
3054 UNREACHABLE();
3055 break;
3056 }
3057 }
3058 break;
3059 }
3060
3061 case EOpMix:
3062 {
3063 ASSERT(basicType == EbtFloat);
3064 resultArray = new TConstantUnion[maxObjectSize];
3065 for (size_t i = 0; i < maxObjectSize; i++)
3066 {
3067 float x = unionArrays[0][i].getFConst();
3068 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003069 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003070 if (type == EbtFloat)
3071 {
3072 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3073 float a = unionArrays[2][i].getFConst();
3074 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3075 }
3076 else // 3rd parameter is EbtBool
3077 {
3078 ASSERT(type == EbtBool);
3079 // Selects which vector each returned component comes from.
3080 // For a component of a that is false, the corresponding component of x is
3081 // returned.
3082 // For a component of a that is true, the corresponding component of y is
3083 // returned.
3084 bool a = unionArrays[2][i].getBConst();
3085 resultArray[i].setFConst(a ? y : x);
3086 }
3087 }
3088 break;
3089 }
3090
3091 case EOpSmoothStep:
3092 {
3093 ASSERT(basicType == EbtFloat);
3094 resultArray = new TConstantUnion[maxObjectSize];
3095 for (size_t i = 0; i < maxObjectSize; i++)
3096 {
3097 float edge0 = unionArrays[0][i].getFConst();
3098 float edge1 = unionArrays[1][i].getFConst();
3099 float x = unionArrays[2][i].getFConst();
3100 // Results are undefined if edge0 >= edge1.
3101 if (edge0 >= edge1)
3102 {
3103 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3104 }
3105 else
3106 {
3107 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3108 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3109 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3110 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3111 }
3112 }
3113 break;
3114 }
3115
Olli Etuaho74da73f2017-02-01 15:37:48 +00003116 case EOpLdexp:
3117 {
3118 resultArray = new TConstantUnion[maxObjectSize];
3119 for (size_t i = 0; i < maxObjectSize; i++)
3120 {
3121 float x = unionArrays[0][i].getFConst();
3122 int exp = unionArrays[1][i].getIConst();
3123 if (exp > 128)
3124 {
3125 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3126 }
3127 else
3128 {
3129 resultArray[i].setFConst(gl::Ldexp(x, exp));
3130 }
3131 }
3132 break;
3133 }
3134
Olli Etuaho51182ab2017-01-22 00:12:29 +00003135 case EOpFaceForward:
3136 {
3137 ASSERT(basicType == EbtFloat);
3138 // genType faceforward(genType N, genType I, genType Nref) :
3139 // If dot(Nref, I) < 0 return N, otherwise return -N.
3140 resultArray = new TConstantUnion[maxObjectSize];
3141 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3142 for (size_t i = 0; i < maxObjectSize; i++)
3143 {
3144 if (dotProduct < 0)
3145 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3146 else
3147 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3148 }
3149 break;
3150 }
3151
3152 case EOpRefract:
3153 {
3154 ASSERT(basicType == EbtFloat);
3155 // genType refract(genType I, genType N, float eta) :
3156 // For the incident vector I and surface normal N, and the ratio of indices of
3157 // refraction eta,
3158 // return the refraction vector. The result is computed by
3159 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3160 // if (k < 0.0)
3161 // return genType(0.0)
3162 // else
3163 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3164 resultArray = new TConstantUnion[maxObjectSize];
3165 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3166 for (size_t i = 0; i < maxObjectSize; i++)
3167 {
3168 float eta = unionArrays[2][i].getFConst();
3169 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3170 if (k < 0.0f)
3171 resultArray[i].setFConst(0.0f);
3172 else
3173 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3174 (eta * dotProduct + sqrtf(k)) *
3175 unionArrays[1][i].getFConst());
3176 }
3177 break;
3178 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003179 case EOpBitfieldExtract:
3180 {
3181 resultArray = new TConstantUnion[maxObjectSize];
3182 for (size_t i = 0; i < maxObjectSize; ++i)
3183 {
3184 int offset = unionArrays[1][0].getIConst();
3185 int bits = unionArrays[2][0].getIConst();
3186 if (bits == 0)
3187 {
3188 if (aggregate->getBasicType() == EbtInt)
3189 {
3190 resultArray[i].setIConst(0);
3191 }
3192 else
3193 {
3194 ASSERT(aggregate->getBasicType() == EbtUInt);
3195 resultArray[i].setUConst(0);
3196 }
3197 }
3198 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3199 {
3200 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3201 &resultArray[i]);
3202 }
3203 else
3204 {
3205 // bits can be 32 here, so we need to avoid bit shift overflow.
3206 uint32_t maskMsb = 1u << (bits - 1);
3207 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3208 if (aggregate->getBasicType() == EbtInt)
3209 {
3210 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3211 uint32_t resultUnsigned = (value & mask) >> offset;
3212 if ((resultUnsigned & maskMsb) != 0)
3213 {
3214 // The most significant bits (from bits+1 to the most significant bit)
3215 // should be set to 1.
3216 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3217 resultUnsigned |= higherBitsMask;
3218 }
3219 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3220 }
3221 else
3222 {
3223 ASSERT(aggregate->getBasicType() == EbtUInt);
3224 uint32_t value = unionArrays[0][i].getUConst();
3225 resultArray[i].setUConst((value & mask) >> offset);
3226 }
3227 }
3228 }
3229 break;
3230 }
3231 case EOpBitfieldInsert:
3232 {
3233 resultArray = new TConstantUnion[maxObjectSize];
3234 for (size_t i = 0; i < maxObjectSize; ++i)
3235 {
3236 int offset = unionArrays[2][0].getIConst();
3237 int bits = unionArrays[3][0].getIConst();
3238 if (bits == 0)
3239 {
3240 if (aggregate->getBasicType() == EbtInt)
3241 {
3242 int32_t base = unionArrays[0][i].getIConst();
3243 resultArray[i].setIConst(base);
3244 }
3245 else
3246 {
3247 ASSERT(aggregate->getBasicType() == EbtUInt);
3248 uint32_t base = unionArrays[0][i].getUConst();
3249 resultArray[i].setUConst(base);
3250 }
3251 }
3252 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3253 {
3254 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3255 &resultArray[i]);
3256 }
3257 else
3258 {
3259 // bits can be 32 here, so we need to avoid bit shift overflow.
3260 uint32_t maskMsb = 1u << (bits - 1);
3261 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3262 uint32_t baseMask = ~insertMask;
3263 if (aggregate->getBasicType() == EbtInt)
3264 {
3265 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3266 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3267 uint32_t resultUnsigned =
3268 (base & baseMask) | ((insert << offset) & insertMask);
3269 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3270 }
3271 else
3272 {
3273 ASSERT(aggregate->getBasicType() == EbtUInt);
3274 uint32_t base = unionArrays[0][i].getUConst();
3275 uint32_t insert = unionArrays[1][i].getUConst();
3276 resultArray[i].setUConst((base & baseMask) |
3277 ((insert << offset) & insertMask));
3278 }
3279 }
3280 }
3281 break;
3282 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003283
3284 default:
3285 UNREACHABLE();
3286 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303287 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003288 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303289}
3290
3291// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04003292TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
3293{
3294 if (hashFunction == NULL || name.empty())
3295 return name;
3296 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
3297 TStringStream stream;
3298 stream << HASHED_NAME_PREFIX << std::hex << number;
3299 TString hashedName = stream.str();
3300 return hashedName;
3301}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003302
3303void TIntermTraverser::updateTree()
3304{
Olli Etuahoa6f22092015-05-08 18:31:10 +03003305 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
3306 {
3307 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
3308 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003309 if (!insertion.insertionsAfter.empty())
3310 {
3311 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
3312 insertion.insertionsAfter);
3313 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003314 }
3315 if (!insertion.insertionsBefore.empty())
3316 {
3317 bool inserted =
3318 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
3319 ASSERT(inserted);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03003320 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03003321 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003322 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
3323 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003324 const NodeUpdateEntry &replacement = mReplacements[ii];
3325 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003326 bool replaced =
3327 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003328 ASSERT(replaced);
3329
Olli Etuahocd94ef92015-04-16 19:18:10 +03003330 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003331 {
3332 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03003333 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003334 // be replaced, we need to make sure we don't update the replaced
3335 // node; instead, we update the replacement node.
3336 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
3337 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03003338 NodeUpdateEntry &replacement2 = mReplacements[jj];
3339 if (replacement2.parent == replacement.original)
3340 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003341 }
3342 }
3343 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003344 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
3345 {
3346 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
3347 ASSERT(replacement.parent);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003348 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
3349 replacement.replacements);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03003350 ASSERT(replaced);
3351 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03003352
Jamie Madill03d863c2016-07-27 18:15:53 -04003353 clearReplacementQueue();
3354}
3355
3356void TIntermTraverser::clearReplacementQueue()
3357{
Olli Etuahod4f303e2015-05-20 17:09:06 +03003358 mReplacements.clear();
3359 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04003360 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02003361}
Jamie Madill1048e432016-07-23 18:51:28 -04003362
Jamie Madill03d863c2016-07-27 18:15:53 -04003363void TIntermTraverser::queueReplacement(TIntermNode *original,
3364 TIntermNode *replacement,
3365 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003366{
Jamie Madill03d863c2016-07-27 18:15:53 -04003367 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04003368}
3369
Jamie Madill03d863c2016-07-27 18:15:53 -04003370void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
3371 TIntermNode *original,
3372 TIntermNode *replacement,
3373 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04003374{
Jamie Madill03d863c2016-07-27 18:15:53 -04003375 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
3376 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04003377}
Jamie Madill45bcc782016-11-07 13:58:48 -05003378
Olli Etuahofe486322017-03-21 09:30:54 +00003379TName TIntermTraverser::GetInternalFunctionName(const char *name)
3380{
3381 TString nameStr(name);
3382 nameStr = TFunction::mangleName(nameStr);
3383 TName nameObj(nameStr);
3384 nameObj.setInternal(true);
3385 return nameObj;
3386}
3387
3388TIntermFunctionPrototype *TIntermTraverser::CreateInternalFunctionPrototypeNode(
3389 const TType &returnType,
3390 const char *name,
3391 const TSymbolUniqueId &functionId)
3392{
3393 TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType, functionId);
3394 functionNode->getFunctionSymbolInfo()->setNameObj(GetInternalFunctionName(name));
3395 return functionNode;
3396}
3397
3398TIntermFunctionDefinition *TIntermTraverser::CreateInternalFunctionDefinitionNode(
3399 const TType &returnType,
3400 const char *name,
3401 TIntermBlock *functionBody,
3402 const TSymbolUniqueId &functionId)
3403{
3404 TIntermFunctionPrototype *prototypeNode =
3405 CreateInternalFunctionPrototypeNode(returnType, name, functionId);
3406 return new TIntermFunctionDefinition(prototypeNode, functionBody);
3407}
3408
3409TIntermAggregate *TIntermTraverser::CreateInternalFunctionCallNode(
3410 const TType &returnType,
3411 const char *name,
3412 const TSymbolUniqueId &functionId,
3413 TIntermSequence *arguments)
3414{
3415 TIntermAggregate *functionNode = TIntermAggregate::CreateFunctionCall(
3416 returnType, functionId, GetInternalFunctionName(name), arguments);
3417 return functionNode;
3418}
3419
Jamie Madill45bcc782016-11-07 13:58:48 -05003420} // namespace sh