blob: 1d92ee0e8f99a461032041c721695ae5a3374a69 [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/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040023#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040024
Jamie Madill45bcc782016-11-07 13:58:48 -050025namespace sh
26{
27
Jamie Madillb1a85f42014-08-19 15:23:24 -040028namespace
29{
30
Jamie Madilld7b1ab52016-12-12 14:42:19 -050031const float kPi = 3.14159265358979323846f;
Arun Patole9dea48f2015-04-02 11:45:09 +053032const float kDegreesToRadiansMultiplier = kPi / 180.0f;
33const float kRadiansToDegreesMultiplier = 180.0f / kPi;
34
Jamie Madillb1a85f42014-08-19 15:23:24 -040035TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
36{
37 return left > right ? left : right;
38}
39
Arun Patole274f0702015-05-05 13:33:30 +053040TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
41{
42 TConstantUnion *constUnion = new TConstantUnion[size];
43 for (unsigned int i = 0; i < size; ++i)
Jamie Madilld7b1ab52016-12-12 14:42:19 -050044 constUnion[i] = constant;
Arun Patole274f0702015-05-05 13:33:30 +053045
46 return constUnion;
47}
48
Olli Etuahof119a262016-08-19 15:54:22 +030049void UndefinedConstantFoldingError(const TSourceLoc &loc,
50 TOperator op,
51 TBasicType basicType,
52 TDiagnostics *diagnostics,
53 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053054{
Olli Etuahof119a262016-08-19 15:54:22 +030055 diagnostics->warning(loc, "operation result is undefined for the values passed in",
Olli Etuaho4de340a2016-12-16 09:32:03 +000056 GetOperatorString(op));
Arun Patolebf790422015-05-18 17:53:04 +053057
58 switch (basicType)
59 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050060 case EbtFloat:
61 result->setFConst(0.0f);
62 break;
63 case EbtInt:
64 result->setIConst(0);
65 break;
66 case EbtUInt:
67 result->setUConst(0u);
68 break;
69 case EbtBool:
70 result->setBConst(false);
71 break;
72 default:
73 break;
Arun Patolebf790422015-05-18 17:53:04 +053074 }
75}
76
Olli Etuaho5c0e0232015-11-11 15:55:59 +020077float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053078{
79 float result = 0.0f;
80 for (size_t i = 0; i < paramArraySize; i++)
81 {
82 float f = paramArray[i].getFConst();
83 result += f * f;
84 }
85 return sqrtf(result);
86}
87
Olli Etuaho5c0e0232015-11-11 15:55:59 +020088float VectorDotProduct(const TConstantUnion *paramArray1,
89 const TConstantUnion *paramArray2,
90 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053091{
92 float result = 0.0f;
93 for (size_t i = 0; i < paramArraySize; i++)
94 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
95 return result;
96}
97
Olli Etuaho3272a6d2016-08-29 17:54:50 +030098TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
Olli Etuaho7c3848e2015-11-04 13:19:17 +020099 const TIntermTyped *originalNode,
100 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300101{
102 if (constArray == nullptr)
103 {
104 return nullptr;
105 }
106 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200107 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300108 folded->setLine(originalNode->getLine());
109 return folded;
110}
111
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200112angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
113 const unsigned int &rows,
114 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530115{
116 std::vector<float> elements;
117 for (size_t i = 0; i < rows * cols; i++)
118 elements.push_back(paramArray[i].getFConst());
119 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300120 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
121 // so that the created matrix will have the expected dimensions after the transpose.
122 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530123}
124
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200125angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530126{
127 std::vector<float> elements;
128 for (size_t i = 0; i < size * size; i++)
129 elements.push_back(paramArray[i].getFConst());
130 // Transpose is used since the Matrix constructor expects arguments in row-major order,
131 // whereas the paramArray is in column-major order.
132 return angle::Matrix<float>(elements, size).transpose();
133}
134
135void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
136{
137 // Transpose is used since the input Matrix is in row-major order,
138 // whereas the actual result should be in column-major order.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500139 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530140 std::vector<float> resultElements = result.elements();
141 for (size_t i = 0; i < resultElements.size(); i++)
142 resultArray[i].setFConst(resultElements[i]);
143}
144
Jamie Madillb1a85f42014-08-19 15:23:24 -0400145} // namespace anonymous
146
Jamie Madillb1a85f42014-08-19 15:23:24 -0400147////////////////////////////////////////////////////////////////
148//
149// Member functions of the nodes used for building the tree.
150//
151////////////////////////////////////////////////////////////////
152
Olli Etuahod2a67b92014-10-21 16:42:57 +0300153void TIntermTyped::setTypePreservePrecision(const TType &t)
154{
155 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500156 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300157 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
158 mType.setPrecision(precision);
159}
160
Jamie Madillb1a85f42014-08-19 15:23:24 -0400161#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500162 if (node == original) \
163 { \
164 node = static_cast<type *>(replacement); \
165 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400166 }
167
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500168bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400169{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300170 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400171 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
172 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
173 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100174 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400175 return false;
176}
177
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500178bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400179{
180 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
181 return false;
182}
183
Olli Etuahob6fa0432016-09-28 16:28:05 +0100184bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
185{
186 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
187 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
188 return false;
189}
190
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500191bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400192{
193 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
194 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
195 return false;
196}
197
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500198bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400199{
Olli Etuahoa2234302016-08-31 12:05:39 +0300200 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400201 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
202 return false;
203}
204
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000205bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
206{
207 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
208 return false;
209}
210
Olli Etuaho336b1472016-10-05 16:37:55 +0100211bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
212{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000213 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100214 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
215 return false;
216}
217
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500218bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400219{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100220 return replaceChildNodeInternal(original, replacement);
221}
222
223bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
224{
225 return replaceChildNodeInternal(original, replacement);
226}
227
Olli Etuaho16c745a2017-01-16 17:02:27 +0000228bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
229{
230 return replaceChildNodeInternal(original, replacement);
231}
232
Olli Etuaho13389b62016-10-16 11:48:18 +0100233bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
234{
235 return replaceChildNodeInternal(original, replacement);
236}
237
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100238bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
239{
240 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400241 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100242 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400243 }
244 return false;
245}
246
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100247bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
248 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300249{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100250 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300251 {
252 if (*it == original)
253 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100254 it = getSequence()->erase(it);
255 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300256 return true;
257 }
258 }
259 return false;
260}
261
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100262bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
263 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300264{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100265 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300266 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300267 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300268 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100269 auto it = getSequence()->begin() + position;
270 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300271 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300272}
273
Olli Etuahofe486322017-03-21 09:30:54 +0000274TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
275 TIntermSequence *arguments)
276{
277 TIntermAggregate *callNode =
278 new TIntermAggregate(func.getReturnType(), EOpCallFunctionInAST, arguments);
279 callNode->getFunctionSymbolInfo()->setFromFunction(func);
280 return callNode;
281}
282
283TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TType &type,
284 const TSymbolUniqueId &id,
285 const TName &name,
286 TIntermSequence *arguments)
287{
288 TIntermAggregate *callNode = new TIntermAggregate(type, EOpCallFunctionInAST, arguments);
289 callNode->getFunctionSymbolInfo()->setId(id);
290 callNode->getFunctionSymbolInfo()->setNameObj(name);
291 return callNode;
292}
293
294TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
295 TIntermSequence *arguments)
296{
297 TIntermAggregate *callNode =
298 new TIntermAggregate(func.getReturnType(), EOpCallBuiltInFunction, arguments);
299 callNode->getFunctionSymbolInfo()->setFromFunction(func);
300 // Note that name needs to be set before texture function type is determined.
301 callNode->setBuiltInFunctionPrecision();
302 return callNode;
303}
304
305TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000306 TIntermSequence *arguments)
307{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300308 return new TIntermAggregate(type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000309}
310
311TIntermAggregate *TIntermAggregate::Create(const TType &type,
312 TOperator op,
313 TIntermSequence *arguments)
314{
315 TIntermAggregate *node = new TIntermAggregate(type, op, arguments);
316 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
317 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
318 ASSERT(!node->isConstructor()); // Should use CreateConstructor
319 return node;
320}
321
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800322TIntermAggregate::TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments)
323 : TIntermOperator(op), mUseEmulatedFunction(false), mGotPrecisionFromChildren(false)
324{
325 if (arguments != nullptr)
326 {
327 mArguments.swap(*arguments);
328 }
329 setTypePrecisionAndQualifier(type);
330}
331
332void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
333{
334 setType(type);
335 mType.setQualifier(EvqTemporary);
336 if (!isFunctionCall())
337 {
338 if (isConstructor())
339 {
340 // Structs should not be precision qualified, the individual members may be.
341 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300342 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800343 {
344 setPrecisionFromChildren();
345 }
346 }
347 else
348 {
349 setPrecisionForBuiltInOp();
350 }
351 if (areChildrenConstQualified())
352 {
353 mType.setQualifier(EvqConst);
354 }
355 }
356}
357
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200358bool TIntermAggregate::areChildrenConstQualified()
359{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800360 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200361 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800362 TIntermTyped *typedArg = arg->getAsTyped();
363 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200364 {
365 return false;
366 }
367 }
368 return true;
369}
370
Olli Etuahod2a67b92014-10-21 16:42:57 +0300371void TIntermAggregate::setPrecisionFromChildren()
372{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300373 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300374 if (getBasicType() == EbtBool)
375 {
376 mType.setPrecision(EbpUndefined);
377 return;
378 }
379
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500380 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800381 TIntermSequence::iterator childIter = mArguments.begin();
382 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300383 {
384 TIntermTyped *typed = (*childIter)->getAsTyped();
385 if (typed)
386 precision = GetHigherPrecision(typed->getPrecision(), precision);
387 ++childIter;
388 }
389 mType.setPrecision(precision);
390}
391
Olli Etuaho9250cb22017-01-21 10:51:27 +0000392void TIntermAggregate::setPrecisionForBuiltInOp()
393{
394 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800395 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000396 if (!setPrecisionForSpecialBuiltInOp())
397 {
398 setPrecisionFromChildren();
399 }
400}
401
402bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
403{
404 switch (mOp)
405 {
406 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800407 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
408 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000409 return true;
410 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800411 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
412 mArguments[1]->getAsTyped()->getPrecision()));
413 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000414 return true;
415 case EOpUaddCarry:
416 case EOpUsubBorrow:
417 mType.setPrecision(EbpHigh);
418 return true;
419 default:
420 return false;
421 }
422}
423
Olli Etuahod2a67b92014-10-21 16:42:57 +0300424void TIntermAggregate::setBuiltInFunctionPrecision()
425{
426 // All built-ins returning bool should be handled as ops, not functions.
427 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800428 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300429
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800430 TPrecision precision = EbpUndefined;
431 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300432 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800433 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300434 // ESSL spec section 8: texture functions get their precision from the sampler.
435 if (typed && IsSampler(typed->getBasicType()))
436 {
437 precision = typed->getPrecision();
438 break;
439 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300440 }
441 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
442 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100443 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300444 mType.setPrecision(EbpHigh);
445 else
446 mType.setPrecision(precision);
447}
448
Olli Etuahof2209f72017-04-01 12:45:55 +0300449TString TIntermAggregate::getSymbolTableMangledName() const
450{
451 ASSERT(!isConstructor());
452 switch (mOp)
453 {
454 case EOpCallInternalRawFunction:
455 case EOpCallBuiltInFunction:
456 case EOpCallFunctionInAST:
457 return TFunction::GetMangledNameFromCall(mFunctionInfo.getName(), mArguments);
458 default:
459 TString opString = GetOperatorString(mOp);
460 return TFunction::GetMangledNameFromCall(opString, mArguments);
461 }
462}
463
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300464bool TIntermAggregate::hasSideEffects() const
465{
466 if (isFunctionCall() && mFunctionInfo.isKnownToNotHaveSideEffects())
467 {
468 for (TIntermNode *arg : mArguments)
469 {
470 if (arg->getAsTyped()->hasSideEffects())
471 {
472 return true;
473 }
474 }
475 return false;
476 }
477 // Conservatively assume most aggregate operators have side-effects
478 return true;
479}
480
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100481void TIntermBlock::appendStatement(TIntermNode *statement)
482{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300483 // Declaration nodes with no children can appear if it was an empty declaration or if all the
484 // declarators just added constants to the symbol table instead of generating code. We still
485 // need to add the declaration to the AST in that case because it might be relevant to the
486 // validity of switch/case.
487 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100488 {
489 mStatements.push_back(statement);
490 }
491}
492
Olli Etuaho16c745a2017-01-16 17:02:27 +0000493void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
494{
495 ASSERT(parameter != nullptr);
496 mParameters.push_back(parameter);
497}
498
Olli Etuaho13389b62016-10-16 11:48:18 +0100499void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
500{
501 ASSERT(declarator != nullptr);
502 ASSERT(declarator->getAsSymbolNode() != nullptr ||
503 (declarator->getAsBinaryNode() != nullptr &&
504 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
505 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300506 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100507 mDeclarators.push_back(declarator);
508}
509
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300510bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
511{
512 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
513 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
514 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
515 return false;
516}
517
Olli Etuaho57961272016-09-14 13:57:46 +0300518bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400519{
520 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100521 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
522 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400523 return false;
524}
525
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500526bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200527{
528 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100529 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300530 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200531 return false;
532}
533
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500534bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200535{
536 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
537 return false;
538}
539
Olli Etuahod7a25242015-08-18 13:49:45 +0300540TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
541{
542 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
543 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
544 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
545 mLine = node.mLine;
546}
547
Olli Etuahod4f4c112016-04-15 15:11:24 +0300548bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
549{
550 TIntermAggregate *constructor = getAsAggregate();
551 if (!constructor || !constructor->isConstructor())
552 {
553 return false;
554 }
555 for (TIntermNode *&node : *constructor->getSequence())
556 {
557 if (!node->getAsConstantUnion())
558 return false;
559 }
560 return true;
561}
562
Olli Etuahod7a25242015-08-18 13:49:45 +0300563TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
564{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200565 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300566}
567
Olli Etuahobd674552016-10-06 13:28:42 +0100568void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
569{
Olli Etuahoec9232b2017-03-27 17:01:37 +0300570 setName(function.getName());
Olli Etuahofe486322017-03-21 09:30:54 +0000571 setId(TSymbolUniqueId(function));
572}
573
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300574TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id)
575 : mId(new TSymbolUniqueId(id)), mKnownToNotHaveSideEffects(false)
Olli Etuahofe486322017-03-21 09:30:54 +0000576{
577}
578
579TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300580 : mName(info.mName), mId(nullptr), mKnownToNotHaveSideEffects(info.mKnownToNotHaveSideEffects)
Olli Etuahofe486322017-03-21 09:30:54 +0000581{
582 if (info.mId)
583 {
584 mId = new TSymbolUniqueId(*info.mId);
585 }
586}
587
588TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
589{
590 mName = info.mName;
591 if (info.mId)
592 {
593 mId = new TSymbolUniqueId(*info.mId);
594 }
595 else
596 {
597 mId = nullptr;
598 }
599 return *this;
600}
601
602void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
603{
604 mId = new TSymbolUniqueId(id);
605}
606
607const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
608{
609 ASSERT(mId);
610 return *mId;
Olli Etuahobd674552016-10-06 13:28:42 +0100611}
612
Olli Etuahod7a25242015-08-18 13:49:45 +0300613TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
614 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300615 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100616 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
617 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300618{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800619 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300620 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800621 TIntermTyped *typedArg = arg->getAsTyped();
622 ASSERT(typedArg != nullptr);
623 TIntermTyped *argCopy = typedArg->deepCopy();
624 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300625 }
626}
627
Olli Etuahofe486322017-03-21 09:30:54 +0000628TIntermAggregate *TIntermAggregate::shallowCopy() const
629{
630 TIntermSequence *copySeq = new TIntermSequence();
631 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
632 TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq);
633 *copyNode->getFunctionSymbolInfo() = mFunctionInfo;
634 copyNode->setLine(mLine);
635 return copyNode;
636}
637
Olli Etuahob6fa0432016-09-28 16:28:05 +0100638TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
639{
640 TIntermTyped *operandCopy = node.mOperand->deepCopy();
641 ASSERT(operandCopy != nullptr);
642 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000643 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100644}
645
Olli Etuahod7a25242015-08-18 13:49:45 +0300646TIntermBinary::TIntermBinary(const TIntermBinary &node)
647 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
648{
649 TIntermTyped *leftCopy = node.mLeft->deepCopy();
650 TIntermTyped *rightCopy = node.mRight->deepCopy();
651 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
652 mLeft = leftCopy;
653 mRight = rightCopy;
654}
655
656TIntermUnary::TIntermUnary(const TIntermUnary &node)
657 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
658{
659 TIntermTyped *operandCopy = node.mOperand->deepCopy();
660 ASSERT(operandCopy != nullptr);
661 mOperand = operandCopy;
662}
663
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300664TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300665{
Olli Etuahod7a25242015-08-18 13:49:45 +0300666 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300667 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
668 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300669 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300670 mCondition = conditionCopy;
671 mTrueExpression = trueCopy;
672 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300673}
674
Jamie Madillb1a85f42014-08-19 15:23:24 -0400675bool TIntermOperator::isAssignment() const
676{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300677 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400678}
679
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300680bool TIntermOperator::isMultiplication() const
681{
682 switch (mOp)
683 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500684 case EOpMul:
685 case EOpMatrixTimesMatrix:
686 case EOpMatrixTimesVector:
687 case EOpMatrixTimesScalar:
688 case EOpVectorTimesMatrix:
689 case EOpVectorTimesScalar:
690 return true;
691 default:
692 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300693 }
694}
695
Jamie Madillb1a85f42014-08-19 15:23:24 -0400696bool TIntermOperator::isConstructor() const
697{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300698 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400699}
700
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800701bool TIntermOperator::isFunctionCall() const
702{
703 switch (mOp)
704 {
705 case EOpCallFunctionInAST:
706 case EOpCallBuiltInFunction:
707 case EOpCallInternalRawFunction:
708 return true;
709 default:
710 return false;
711 }
712}
713
Olli Etuaho1dded802016-08-18 18:13:13 +0300714TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
715{
716 if (left.isMatrix())
717 {
718 if (right.isMatrix())
719 {
720 return EOpMatrixTimesMatrix;
721 }
722 else
723 {
724 if (right.isVector())
725 {
726 return EOpMatrixTimesVector;
727 }
728 else
729 {
730 return EOpMatrixTimesScalar;
731 }
732 }
733 }
734 else
735 {
736 if (right.isMatrix())
737 {
738 if (left.isVector())
739 {
740 return EOpVectorTimesMatrix;
741 }
742 else
743 {
744 return EOpMatrixTimesScalar;
745 }
746 }
747 else
748 {
749 // Neither operand is a matrix.
750 if (left.isVector() == right.isVector())
751 {
752 // Leave as component product.
753 return EOpMul;
754 }
755 else
756 {
757 return EOpVectorTimesScalar;
758 }
759 }
760 }
761}
762
763TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
764{
765 if (left.isMatrix())
766 {
767 if (right.isMatrix())
768 {
769 return EOpMatrixTimesMatrixAssign;
770 }
771 else
772 {
773 // right should be scalar, but this may not be validated yet.
774 return EOpMatrixTimesScalarAssign;
775 }
776 }
777 else
778 {
779 if (right.isMatrix())
780 {
781 // Left should be a vector, but this may not be validated yet.
782 return EOpVectorTimesMatrixAssign;
783 }
784 else
785 {
786 // Neither operand is a matrix.
787 if (left.isVector() == right.isVector())
788 {
789 // Leave as component product.
790 return EOpMulAssign;
791 }
792 else
793 {
794 // left should be vector and right should be scalar, but this may not be validated
795 // yet.
796 return EOpVectorTimesScalarAssign;
797 }
798 }
799 }
800}
801
Jamie Madillb1a85f42014-08-19 15:23:24 -0400802//
803// Make sure the type of a unary operator is appropriate for its
804// combination of operation and operand type.
805//
Olli Etuahoa2234302016-08-31 12:05:39 +0300806void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400807{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300808 if (mOp == EOpArrayLength)
809 {
810 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
811 setType(TType(EbtInt, EbpUndefined, EvqConst));
812 return;
813 }
814
Olli Etuahoa2234302016-08-31 12:05:39 +0300815 TQualifier resultQualifier = EvqTemporary;
816 if (mOperand->getQualifier() == EvqConst)
817 resultQualifier = EvqConst;
818
819 unsigned char operandPrimarySize =
820 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400821 switch (mOp)
822 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300823 case EOpFloatBitsToInt:
824 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
825 break;
826 case EOpFloatBitsToUint:
827 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
828 break;
829 case EOpIntBitsToFloat:
830 case EOpUintBitsToFloat:
831 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
832 break;
833 case EOpPackSnorm2x16:
834 case EOpPackUnorm2x16:
835 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800836 case EOpPackUnorm4x8:
837 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300838 setType(TType(EbtUInt, EbpHigh, resultQualifier));
839 break;
840 case EOpUnpackSnorm2x16:
841 case EOpUnpackUnorm2x16:
842 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
843 break;
844 case EOpUnpackHalf2x16:
845 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
846 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800847 case EOpUnpackUnorm4x8:
848 case EOpUnpackSnorm4x8:
849 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
850 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300851 case EOpAny:
852 case EOpAll:
853 setType(TType(EbtBool, EbpUndefined, resultQualifier));
854 break;
855 case EOpLength:
856 case EOpDeterminant:
857 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
858 break;
859 case EOpTranspose:
860 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
861 static_cast<unsigned char>(mOperand->getType().getRows()),
862 static_cast<unsigned char>(mOperand->getType().getCols())));
863 break;
864 case EOpIsInf:
865 case EOpIsNan:
866 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
867 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000868 case EOpBitfieldReverse:
869 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
870 break;
871 case EOpBitCount:
872 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
873 break;
874 case EOpFindLSB:
875 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
876 break;
877 case EOpFindMSB:
878 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
879 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300880 default:
881 setType(mOperand->getType());
882 mType.setQualifier(resultQualifier);
883 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400884 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300885}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400886
Olli Etuahob6fa0432016-09-28 16:28:05 +0100887TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
888 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
889 mOperand(operand),
890 mSwizzleOffsets(swizzleOffsets)
891{
892 ASSERT(mSwizzleOffsets.size() <= 4);
893 promote();
894}
895
Olli Etuahoa2234302016-08-31 12:05:39 +0300896TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
897 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
898{
899 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400900}
901
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300902TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
903 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
904{
905 promote();
906}
907
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000908TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
909 : TIntermNode(), mSymbol(symbol)
910{
911 ASSERT(symbol);
912 setLine(line);
913}
914
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300915TIntermTernary::TIntermTernary(TIntermTyped *cond,
916 TIntermTyped *trueExpression,
917 TIntermTyped *falseExpression)
918 : TIntermTyped(trueExpression->getType()),
919 mCondition(cond),
920 mTrueExpression(trueExpression),
921 mFalseExpression(falseExpression)
922{
923 getTypePointer()->setQualifier(
924 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
925}
926
Olli Etuaho81629262017-04-19 11:56:01 +0300927TIntermLoop::TIntermLoop(TLoopType type,
928 TIntermNode *init,
929 TIntermTyped *cond,
930 TIntermTyped *expr,
931 TIntermBlock *body)
932 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
933{
934 // Declaration nodes with no children can appear if all the declarators just added constants to
935 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
936 if (mInit && mInit->getAsDeclarationNode() &&
937 mInit->getAsDeclarationNode()->getSequence()->empty())
938 {
939 mInit = nullptr;
940 }
941}
942
Olli Etuaho923ecef2017-10-11 12:01:38 +0300943TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
944 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
945{
946 // Prune empty false blocks so that there won't be unnecessary operations done on it.
947 if (mFalseBlock && mFalseBlock->getSequence()->empty())
948 {
949 mFalseBlock = nullptr;
950 }
951}
952
953TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
954 : TIntermNode(), mInit(init), mStatementList(statementList)
955{
956 ASSERT(mStatementList);
957}
958
959void TIntermSwitch::setStatementList(TIntermBlock *statementList)
960{
961 ASSERT(statementList);
962 mStatementList = statementList;
963}
964
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300965// static
966TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
967 TIntermTyped *trueExpression,
968 TIntermTyped *falseExpression)
969{
970 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
971 falseExpression->getQualifier() == EvqConst)
972 {
973 return EvqConst;
974 }
975 return EvqTemporary;
976}
977
Olli Etuahoeb7f90f2017-07-07 17:25:23 +0300978TIntermTyped *TIntermTernary::fold()
979{
980 if (mCondition->getAsConstantUnion())
981 {
982 if (mCondition->getAsConstantUnion()->getBConst(0))
983 {
984 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
985 return mTrueExpression;
986 }
987 else
988 {
989 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
990 return mFalseExpression;
991 }
992 }
993 return this;
994}
995
Olli Etuahob6fa0432016-09-28 16:28:05 +0100996void TIntermSwizzle::promote()
997{
998 TQualifier resultQualifier = EvqTemporary;
999 if (mOperand->getQualifier() == EvqConst)
1000 resultQualifier = EvqConst;
1001
1002 auto numFields = mSwizzleOffsets.size();
1003 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1004 static_cast<unsigned char>(numFields)));
1005}
1006
1007bool TIntermSwizzle::hasDuplicateOffsets() const
1008{
1009 int offsetCount[4] = {0u, 0u, 0u, 0u};
1010 for (const auto offset : mSwizzleOffsets)
1011 {
1012 offsetCount[offset]++;
1013 if (offsetCount[offset] > 1)
1014 {
1015 return true;
1016 }
1017 }
1018 return false;
1019}
1020
Olli Etuaho09b04a22016-12-15 13:30:26 +00001021bool TIntermSwizzle::offsetsMatch(int offset) const
1022{
1023 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1024}
1025
Olli Etuahob6fa0432016-09-28 16:28:05 +01001026void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1027{
1028 for (const int offset : mSwizzleOffsets)
1029 {
1030 switch (offset)
1031 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001032 case 0:
1033 *out << "x";
1034 break;
1035 case 1:
1036 *out << "y";
1037 break;
1038 case 2:
1039 *out << "z";
1040 break;
1041 case 3:
1042 *out << "w";
1043 break;
1044 default:
1045 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001046 }
1047 }
1048}
1049
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001050TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1051 const TIntermTyped *left,
1052 const TIntermTyped *right)
1053{
1054 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1055 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1056 right->getQualifier() != EvqConst)
1057 {
1058 return EvqTemporary;
1059 }
1060 return EvqConst;
1061}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001062
1063// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001064void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001065{
Olli Etuaho1dded802016-08-18 18:13:13 +03001066 ASSERT(!isMultiplication() ||
1067 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1068
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001069 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1070 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001071 if (mOp == EOpComma)
1072 {
1073 setType(mRight->getType());
1074 return;
1075 }
1076
Jamie Madillb1a85f42014-08-19 15:23:24 -04001077 // Base assumption: just make the type the same as the left
1078 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001079 setType(mLeft->getType());
1080
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001081 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001082 // Binary operations results in temporary variables unless both
1083 // operands are const.
1084 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1085 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001086 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001087 getTypePointer()->setQualifier(EvqTemporary);
1088 }
1089
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001090 // Handle indexing ops.
1091 switch (mOp)
1092 {
1093 case EOpIndexDirect:
1094 case EOpIndexIndirect:
1095 if (mLeft->isArray())
1096 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001097 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001098 }
1099 else if (mLeft->isMatrix())
1100 {
1101 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1102 static_cast<unsigned char>(mLeft->getRows())));
1103 }
1104 else if (mLeft->isVector())
1105 {
1106 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1107 }
1108 else
1109 {
1110 UNREACHABLE();
1111 }
1112 return;
1113 case EOpIndexDirectStruct:
1114 {
1115 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1116 const int i = mRight->getAsConstantUnion()->getIConst(0);
1117 setType(*fields[i]->type());
1118 getTypePointer()->setQualifier(resultQualifier);
1119 return;
1120 }
1121 case EOpIndexDirectInterfaceBlock:
1122 {
1123 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1124 const int i = mRight->getAsConstantUnion()->getIConst(0);
1125 setType(*fields[i]->type());
1126 getTypePointer()->setQualifier(resultQualifier);
1127 return;
1128 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001129 default:
1130 break;
1131 }
1132
1133 ASSERT(mLeft->isArray() == mRight->isArray());
1134
1135 // The result gets promoted to the highest precision.
1136 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1137 getTypePointer()->setPrecision(higherPrecision);
1138
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001139 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001140
1141 //
1142 // All scalars or structs. Code after this test assumes this case is removed!
1143 //
1144 if (nominalSize == 1)
1145 {
1146 switch (mOp)
1147 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001148 //
1149 // Promote to conditional
1150 //
1151 case EOpEqual:
1152 case EOpNotEqual:
1153 case EOpLessThan:
1154 case EOpGreaterThan:
1155 case EOpLessThanEqual:
1156 case EOpGreaterThanEqual:
1157 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1158 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001159
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001160 //
1161 // And and Or operate on conditionals
1162 //
1163 case EOpLogicalAnd:
1164 case EOpLogicalXor:
1165 case EOpLogicalOr:
1166 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1167 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1168 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001169
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001170 default:
1171 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001172 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001173 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001174 }
1175
1176 // If we reach here, at least one of the operands is vector or matrix.
1177 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001178 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001179
Jamie Madillb1a85f42014-08-19 15:23:24 -04001180 switch (mOp)
1181 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001182 case EOpMul:
1183 break;
1184 case EOpMatrixTimesScalar:
1185 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001186 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001187 setType(TType(basicType, higherPrecision, resultQualifier,
1188 static_cast<unsigned char>(mRight->getCols()),
1189 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001190 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001191 break;
1192 case EOpMatrixTimesVector:
1193 setType(TType(basicType, higherPrecision, resultQualifier,
1194 static_cast<unsigned char>(mLeft->getRows()), 1));
1195 break;
1196 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001197 setType(TType(basicType, higherPrecision, resultQualifier,
1198 static_cast<unsigned char>(mRight->getCols()),
1199 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001200 break;
1201 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001202 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001203 static_cast<unsigned char>(nominalSize), 1));
1204 break;
1205 case EOpVectorTimesMatrix:
1206 setType(TType(basicType, higherPrecision, resultQualifier,
1207 static_cast<unsigned char>(mRight->getCols()), 1));
1208 break;
1209 case EOpMulAssign:
1210 case EOpVectorTimesScalarAssign:
1211 case EOpVectorTimesMatrixAssign:
1212 case EOpMatrixTimesScalarAssign:
1213 case EOpMatrixTimesMatrixAssign:
1214 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1215 break;
1216 case EOpAssign:
1217 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001218 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1219 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1220 break;
1221 case EOpAdd:
1222 case EOpSub:
1223 case EOpDiv:
1224 case EOpIMod:
1225 case EOpBitShiftLeft:
1226 case EOpBitShiftRight:
1227 case EOpBitwiseAnd:
1228 case EOpBitwiseXor:
1229 case EOpBitwiseOr:
1230 case EOpAddAssign:
1231 case EOpSubAssign:
1232 case EOpDivAssign:
1233 case EOpIModAssign:
1234 case EOpBitShiftLeftAssign:
1235 case EOpBitShiftRightAssign:
1236 case EOpBitwiseAndAssign:
1237 case EOpBitwiseXorAssign:
1238 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001239 {
1240 const int secondarySize =
1241 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1242 setType(TType(basicType, higherPrecision, resultQualifier,
1243 static_cast<unsigned char>(nominalSize),
1244 static_cast<unsigned char>(secondarySize)));
1245 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001246 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001247 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001248 case EOpEqual:
1249 case EOpNotEqual:
1250 case EOpLessThan:
1251 case EOpGreaterThan:
1252 case EOpLessThanEqual:
1253 case EOpGreaterThanEqual:
1254 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1255 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001256 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001257 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001258
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001259 case EOpIndexDirect:
1260 case EOpIndexIndirect:
1261 case EOpIndexDirectInterfaceBlock:
1262 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001263 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001264 UNREACHABLE();
1265 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001266 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001267 UNREACHABLE();
1268 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001269 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001270}
1271
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001272const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001273{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001274 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001275 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001276 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001277 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001278 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001279 size_t arrayElementSize = arrayElementType.getObjectSize();
1280 return &mUnionArrayPointer[arrayElementSize * index];
1281 }
1282 else if (isMatrix())
1283 {
1284 ASSERT(index < getType().getCols());
1285 int size = getType().getRows();
1286 return &mUnionArrayPointer[size * index];
1287 }
1288 else if (isVector())
1289 {
1290 ASSERT(index < getType().getNominalSize());
1291 return &mUnionArrayPointer[index];
1292 }
1293 else
1294 {
1295 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001296 return nullptr;
1297 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001298}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001299
Olli Etuahob6fa0432016-09-28 16:28:05 +01001300TIntermTyped *TIntermSwizzle::fold()
1301{
1302 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1303 if (operandConstant == nullptr)
1304 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001305 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001306 }
1307
1308 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1309 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1310 {
1311 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1312 }
1313 return CreateFoldedNode(constArray, this, mType.getQualifier());
1314}
1315
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001316TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1317{
1318 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1319 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1320 switch (mOp)
1321 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001322 case EOpComma:
1323 {
1324 if (mLeft->hasSideEffects())
1325 {
1326 return this;
1327 }
1328 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1329 return mRight;
1330 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001331 case EOpIndexDirect:
1332 {
1333 if (leftConstant == nullptr || rightConstant == nullptr)
1334 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001335 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001336 }
1337 int index = rightConstant->getIConst(0);
1338
1339 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001340 if (!constArray)
1341 {
1342 return this;
1343 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001344 return CreateFoldedNode(constArray, this, mType.getQualifier());
1345 }
1346 case EOpIndexDirectStruct:
1347 {
1348 if (leftConstant == nullptr || rightConstant == nullptr)
1349 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001350 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001351 }
1352 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1353 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1354
1355 size_t previousFieldsSize = 0;
1356 for (size_t i = 0; i < index; ++i)
1357 {
1358 previousFieldsSize += fields[i]->type()->getObjectSize();
1359 }
1360
1361 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1362 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1363 }
1364 case EOpIndexIndirect:
1365 case EOpIndexDirectInterfaceBlock:
1366 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001367 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001368 default:
1369 {
1370 if (leftConstant == nullptr || rightConstant == nullptr)
1371 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001372 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001373 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001374 TConstantUnion *constArray =
1375 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001376 if (!constArray)
1377 {
1378 return this;
1379 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001380
1381 // Nodes may be constant folded without being qualified as constant.
1382 return CreateFoldedNode(constArray, this, mType.getQualifier());
1383 }
1384 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001385}
1386
Olli Etuahof119a262016-08-19 15:54:22 +03001387TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001388{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301389 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001390
1391 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301392 {
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001393 if (mOperand->hasSideEffects())
1394 {
1395 return this;
1396 }
1397 constArray = new TConstantUnion[1];
1398 constArray->setIConst(mOperand->getOutermostArraySize());
1399 }
1400 else
1401 {
1402 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1403 if (operandConstant == nullptr)
1404 {
1405 return this;
1406 }
1407
1408 switch (mOp)
1409 {
1410 case EOpAny:
1411 case EOpAll:
1412 case EOpLength:
1413 case EOpTranspose:
1414 case EOpDeterminant:
1415 case EOpInverse:
1416 case EOpPackSnorm2x16:
1417 case EOpUnpackSnorm2x16:
1418 case EOpPackUnorm2x16:
1419 case EOpUnpackUnorm2x16:
1420 case EOpPackHalf2x16:
1421 case EOpUnpackHalf2x16:
1422 case EOpPackUnorm4x8:
1423 case EOpPackSnorm4x8:
1424 case EOpUnpackUnorm4x8:
1425 case EOpUnpackSnorm4x8:
1426 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1427 break;
1428 default:
1429 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1430 break;
1431 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301432 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001433 if (constArray == nullptr)
1434 {
1435 return this;
1436 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001437
1438 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001439 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001440}
1441
Olli Etuahof119a262016-08-19 15:54:22 +03001442TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001443{
1444 // Make sure that all params are constant before actual constant folding.
1445 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001446 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001447 if (param->getAsConstantUnion() == nullptr)
1448 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001449 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001450 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001451 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001452 TConstantUnion *constArray = nullptr;
1453 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001454 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001455 else
Olli Etuahof119a262016-08-19 15:54:22 +03001456 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001457
1458 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001459 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001460}
1461
Jamie Madillb1a85f42014-08-19 15:23:24 -04001462//
1463// The fold functions see if an operation on a constant can be done in place,
1464// without generating run-time code.
1465//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001466// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001467//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001468TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1469 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001470 TDiagnostics *diagnostics,
1471 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001472{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001473 const TConstantUnion *leftArray = getUnionArrayPointer();
1474 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001475
Olli Etuahof119a262016-08-19 15:54:22 +03001476 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001477
1478 size_t objectSize = getType().getObjectSize();
1479
1480 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1481 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1482 {
1483 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1484 }
1485 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1486 {
1487 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001488 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001489 objectSize = rightNode->getType().getObjectSize();
1490 }
1491
1492 TConstantUnion *resultArray = nullptr;
1493
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001494 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001495 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001496 case EOpAdd:
1497 resultArray = new TConstantUnion[objectSize];
1498 for (size_t i = 0; i < objectSize; i++)
1499 resultArray[i] =
1500 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1501 break;
1502 case EOpSub:
1503 resultArray = new TConstantUnion[objectSize];
1504 for (size_t i = 0; i < objectSize; i++)
1505 resultArray[i] =
1506 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1507 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001508
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001509 case EOpMul:
1510 case EOpVectorTimesScalar:
1511 case EOpMatrixTimesScalar:
1512 resultArray = new TConstantUnion[objectSize];
1513 for (size_t i = 0; i < objectSize; i++)
1514 resultArray[i] =
1515 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1516 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001517
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001518 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001519 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001520 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001521 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001522
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001523 const int leftCols = getCols();
1524 const int leftRows = getRows();
1525 const int rightCols = rightNode->getType().getCols();
1526 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001527 const int resultCols = rightCols;
1528 const int resultRows = leftRows;
1529
1530 resultArray = new TConstantUnion[resultCols * resultRows];
1531 for (int row = 0; row < resultRows; row++)
1532 {
1533 for (int column = 0; column < resultCols; column++)
1534 {
1535 resultArray[resultRows * column + row].setFConst(0.0f);
1536 for (int i = 0; i < leftCols; i++)
1537 {
1538 resultArray[resultRows * column + row].setFConst(
1539 resultArray[resultRows * column + row].getFConst() +
1540 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001541 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001542 }
1543 }
1544 }
1545 }
1546 break;
1547
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001548 case EOpDiv:
1549 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001550 {
1551 resultArray = new TConstantUnion[objectSize];
1552 for (size_t i = 0; i < objectSize; i++)
1553 {
1554 switch (getType().getBasicType())
1555 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001556 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001557 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001558 ASSERT(op == EOpDiv);
1559 float dividend = leftArray[i].getFConst();
1560 float divisor = rightArray[i].getFConst();
1561 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001562 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001563 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001564 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001565 diagnostics->warning(
1566 getLine(),
1567 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001568 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001569 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001570 }
1571 else
1572 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001573 diagnostics->warning(getLine(),
1574 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001575 bool negativeResult =
1576 std::signbit(dividend) != std::signbit(divisor);
1577 resultArray[i].setFConst(
1578 negativeResult ? -std::numeric_limits<float>::infinity()
1579 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001580 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001581 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001582 else if (gl::isInf(dividend) && gl::isInf(divisor))
1583 {
1584 diagnostics->warning(getLine(),
1585 "Infinity divided by infinity during constant "
1586 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001587 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001588 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1589 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001590 else
1591 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001592 float result = dividend / divisor;
1593 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001594 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001595 diagnostics->warning(
1596 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001597 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001598 }
1599 resultArray[i].setFConst(result);
1600 }
1601 break;
1602 }
1603 case EbtInt:
1604 if (rightArray[i] == 0)
1605 {
1606 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001607 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001608 resultArray[i].setIConst(INT_MAX);
1609 }
1610 else
1611 {
1612 int lhs = leftArray[i].getIConst();
1613 int divisor = rightArray[i].getIConst();
1614 if (op == EOpDiv)
1615 {
1616 // Check for the special case where the minimum representable number
1617 // is
1618 // divided by -1. If left alone this leads to integer overflow in
1619 // C++.
1620 // ESSL 3.00.6 section 4.1.3 Integers:
1621 // "However, for the case where the minimum representable value is
1622 // divided by -1, it is allowed to return either the minimum
1623 // representable value or the maximum representable value."
1624 if (lhs == -0x7fffffff - 1 && divisor == -1)
1625 {
1626 resultArray[i].setIConst(0x7fffffff);
1627 }
1628 else
1629 {
1630 resultArray[i].setIConst(lhs / divisor);
1631 }
Olli Etuahod4453572016-09-27 13:21:46 +01001632 }
1633 else
1634 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001635 ASSERT(op == EOpIMod);
1636 if (lhs < 0 || divisor < 0)
1637 {
1638 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1639 // when
1640 // either one of the operands is negative.
1641 diagnostics->warning(getLine(),
1642 "Negative modulus operator operand "
1643 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001644 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001645 resultArray[i].setIConst(0);
1646 }
1647 else
1648 {
1649 resultArray[i].setIConst(lhs % divisor);
1650 }
Olli Etuahod4453572016-09-27 13:21:46 +01001651 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001652 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001653 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001654
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001655 case EbtUInt:
1656 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001657 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001658 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001659 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001660 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001661 }
1662 else
1663 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001664 if (op == EOpDiv)
1665 {
1666 resultArray[i].setUConst(leftArray[i].getUConst() /
1667 rightArray[i].getUConst());
1668 }
1669 else
1670 {
1671 ASSERT(op == EOpIMod);
1672 resultArray[i].setUConst(leftArray[i].getUConst() %
1673 rightArray[i].getUConst());
1674 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001675 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001676 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001677
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001678 default:
1679 UNREACHABLE();
1680 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001681 }
1682 }
1683 }
1684 break;
1685
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001686 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001687 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001688 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001689 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001690
1691 const int matrixCols = getCols();
1692 const int matrixRows = getRows();
1693
1694 resultArray = new TConstantUnion[matrixRows];
1695
1696 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1697 {
1698 resultArray[matrixRow].setFConst(0.0f);
1699 for (int col = 0; col < matrixCols; col++)
1700 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001701 resultArray[matrixRow].setFConst(
1702 resultArray[matrixRow].getFConst() +
1703 leftArray[col * matrixRows + matrixRow].getFConst() *
1704 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001705 }
1706 }
1707 }
1708 break;
1709
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001710 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001711 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001712 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001713 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001714
1715 const int matrixCols = rightNode->getType().getCols();
1716 const int matrixRows = rightNode->getType().getRows();
1717
1718 resultArray = new TConstantUnion[matrixCols];
1719
1720 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1721 {
1722 resultArray[matrixCol].setFConst(0.0f);
1723 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1724 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001725 resultArray[matrixCol].setFConst(
1726 resultArray[matrixCol].getFConst() +
1727 leftArray[matrixRow].getFConst() *
1728 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001729 }
1730 }
1731 }
1732 break;
1733
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001734 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001735 {
1736 resultArray = new TConstantUnion[objectSize];
1737 for (size_t i = 0; i < objectSize; i++)
1738 {
1739 resultArray[i] = leftArray[i] && rightArray[i];
1740 }
1741 }
1742 break;
1743
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001744 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001745 {
1746 resultArray = new TConstantUnion[objectSize];
1747 for (size_t i = 0; i < objectSize; i++)
1748 {
1749 resultArray[i] = leftArray[i] || rightArray[i];
1750 }
1751 }
1752 break;
1753
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001754 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001755 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001756 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001757 resultArray = new TConstantUnion[objectSize];
1758 for (size_t i = 0; i < objectSize; i++)
1759 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001760 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001761 }
1762 }
1763 break;
1764
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001765 case EOpBitwiseAnd:
1766 resultArray = new TConstantUnion[objectSize];
1767 for (size_t i = 0; i < objectSize; i++)
1768 resultArray[i] = leftArray[i] & rightArray[i];
1769 break;
1770 case EOpBitwiseXor:
1771 resultArray = new TConstantUnion[objectSize];
1772 for (size_t i = 0; i < objectSize; i++)
1773 resultArray[i] = leftArray[i] ^ rightArray[i];
1774 break;
1775 case EOpBitwiseOr:
1776 resultArray = new TConstantUnion[objectSize];
1777 for (size_t i = 0; i < objectSize; i++)
1778 resultArray[i] = leftArray[i] | rightArray[i];
1779 break;
1780 case EOpBitShiftLeft:
1781 resultArray = new TConstantUnion[objectSize];
1782 for (size_t i = 0; i < objectSize; i++)
1783 resultArray[i] =
1784 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1785 break;
1786 case EOpBitShiftRight:
1787 resultArray = new TConstantUnion[objectSize];
1788 for (size_t i = 0; i < objectSize; i++)
1789 resultArray[i] =
1790 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1791 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001792
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001793 case EOpLessThan:
1794 ASSERT(objectSize == 1);
1795 resultArray = new TConstantUnion[1];
1796 resultArray->setBConst(*leftArray < *rightArray);
1797 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001798
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001799 case EOpGreaterThan:
1800 ASSERT(objectSize == 1);
1801 resultArray = new TConstantUnion[1];
1802 resultArray->setBConst(*leftArray > *rightArray);
1803 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001804
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001805 case EOpLessThanEqual:
1806 ASSERT(objectSize == 1);
1807 resultArray = new TConstantUnion[1];
1808 resultArray->setBConst(!(*leftArray > *rightArray));
1809 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001810
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001811 case EOpGreaterThanEqual:
1812 ASSERT(objectSize == 1);
1813 resultArray = new TConstantUnion[1];
1814 resultArray->setBConst(!(*leftArray < *rightArray));
1815 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001816
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001817 case EOpEqual:
1818 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001819 {
1820 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001821 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001822 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001823 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001824 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001825 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001826 equal = false;
1827 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001828 }
1829 }
1830 if (op == EOpEqual)
1831 {
1832 resultArray->setBConst(equal);
1833 }
1834 else
1835 {
1836 resultArray->setBConst(!equal);
1837 }
1838 }
1839 break;
1840
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001841 default:
1842 UNREACHABLE();
1843 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001844 }
1845 return resultArray;
1846}
1847
Olli Etuahof119a262016-08-19 15:54:22 +03001848// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1849// code. Returns the constant value to keep using. Nullptr should not be returned.
1850TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001851{
Olli Etuahof119a262016-08-19 15:54:22 +03001852 // Do operations where the return type may have a different number of components compared to the
1853 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001854
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001855 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001856 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301857
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001858 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301859 TConstantUnion *resultArray = nullptr;
1860 switch (op)
1861 {
Olli Etuahof119a262016-08-19 15:54:22 +03001862 case EOpAny:
1863 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301864 resultArray = new TConstantUnion();
1865 resultArray->setBConst(false);
1866 for (size_t i = 0; i < objectSize; i++)
1867 {
1868 if (operandArray[i].getBConst())
1869 {
1870 resultArray->setBConst(true);
1871 break;
1872 }
1873 }
1874 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301875
Olli Etuahof119a262016-08-19 15:54:22 +03001876 case EOpAll:
1877 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301878 resultArray = new TConstantUnion();
1879 resultArray->setBConst(true);
1880 for (size_t i = 0; i < objectSize; i++)
1881 {
1882 if (!operandArray[i].getBConst())
1883 {
1884 resultArray->setBConst(false);
1885 break;
1886 }
1887 }
1888 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301889
Olli Etuahof119a262016-08-19 15:54:22 +03001890 case EOpLength:
1891 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301892 resultArray = new TConstantUnion();
1893 resultArray->setFConst(VectorLength(operandArray, objectSize));
1894 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301895
Olli Etuahof119a262016-08-19 15:54:22 +03001896 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301897 {
Olli Etuahof119a262016-08-19 15:54:22 +03001898 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301899 resultArray = new TConstantUnion[objectSize];
1900 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001901 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301902 SetUnionArrayFromMatrix(result, resultArray);
1903 break;
1904 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301905
Olli Etuahof119a262016-08-19 15:54:22 +03001906 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301907 {
Olli Etuahof119a262016-08-19 15:54:22 +03001908 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301909 unsigned int size = getType().getNominalSize();
1910 ASSERT(size >= 2 && size <= 4);
1911 resultArray = new TConstantUnion();
1912 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1913 break;
1914 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301915
Olli Etuahof119a262016-08-19 15:54:22 +03001916 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301917 {
Olli Etuahof119a262016-08-19 15:54:22 +03001918 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301919 unsigned int size = getType().getNominalSize();
1920 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001921 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301922 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1923 SetUnionArrayFromMatrix(result, resultArray);
1924 break;
1925 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301926
Olli Etuahof119a262016-08-19 15:54:22 +03001927 case EOpPackSnorm2x16:
1928 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301929 ASSERT(getType().getNominalSize() == 2);
1930 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001931 resultArray->setUConst(
1932 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301933 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301934
Olli Etuahof119a262016-08-19 15:54:22 +03001935 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301936 {
Olli Etuahof119a262016-08-19 15:54:22 +03001937 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301938 resultArray = new TConstantUnion[2];
1939 float f1, f2;
1940 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1941 resultArray[0].setFConst(f1);
1942 resultArray[1].setFConst(f2);
1943 break;
1944 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945
Olli Etuahof119a262016-08-19 15:54:22 +03001946 case EOpPackUnorm2x16:
1947 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301948 ASSERT(getType().getNominalSize() == 2);
1949 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001950 resultArray->setUConst(
1951 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301952 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301953
Olli Etuahof119a262016-08-19 15:54:22 +03001954 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301955 {
Olli Etuahof119a262016-08-19 15:54:22 +03001956 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301957 resultArray = new TConstantUnion[2];
1958 float f1, f2;
1959 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1960 resultArray[0].setFConst(f1);
1961 resultArray[1].setFConst(f2);
1962 break;
1963 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301964
Olli Etuahof119a262016-08-19 15:54:22 +03001965 case EOpPackHalf2x16:
1966 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301967 ASSERT(getType().getNominalSize() == 2);
1968 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001969 resultArray->setUConst(
1970 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301971 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301972
Olli Etuahof119a262016-08-19 15:54:22 +03001973 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301974 {
Olli Etuahof119a262016-08-19 15:54:22 +03001975 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301976 resultArray = new TConstantUnion[2];
1977 float f1, f2;
1978 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1979 resultArray[0].setFConst(f1);
1980 resultArray[1].setFConst(f2);
1981 break;
1982 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301983
Olli Etuaho25aef452017-01-29 16:15:44 -08001984 case EOpPackUnorm4x8:
1985 {
1986 ASSERT(getType().getBasicType() == EbtFloat);
1987 resultArray = new TConstantUnion();
1988 resultArray->setUConst(
1989 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1990 operandArray[2].getFConst(), operandArray[3].getFConst()));
1991 break;
1992 }
1993 case EOpPackSnorm4x8:
1994 {
1995 ASSERT(getType().getBasicType() == EbtFloat);
1996 resultArray = new TConstantUnion();
1997 resultArray->setUConst(
1998 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1999 operandArray[2].getFConst(), operandArray[3].getFConst()));
2000 break;
2001 }
2002 case EOpUnpackUnorm4x8:
2003 {
2004 ASSERT(getType().getBasicType() == EbtUInt);
2005 resultArray = new TConstantUnion[4];
2006 float f[4];
2007 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2008 for (size_t i = 0; i < 4; ++i)
2009 {
2010 resultArray[i].setFConst(f[i]);
2011 }
2012 break;
2013 }
2014 case EOpUnpackSnorm4x8:
2015 {
2016 ASSERT(getType().getBasicType() == EbtUInt);
2017 resultArray = new TConstantUnion[4];
2018 float f[4];
2019 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2020 for (size_t i = 0; i < 4; ++i)
2021 {
2022 resultArray[i].setFConst(f[i]);
2023 }
2024 break;
2025 }
2026
Olli Etuahof119a262016-08-19 15:54:22 +03002027 default:
2028 UNREACHABLE();
2029 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302030 }
2031
2032 return resultArray;
2033}
2034
Olli Etuahof119a262016-08-19 15:54:22 +03002035TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2036 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302037{
Olli Etuahof119a262016-08-19 15:54:22 +03002038 // Do unary operations where each component of the result is computed based on the corresponding
2039 // component of the operand. Also folds normalize, though the divisor in that case takes all
2040 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302041
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002042 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002043 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002044
2045 size_t objectSize = getType().getObjectSize();
2046
Arun Patoleab2b9a22015-07-06 18:27:56 +05302047 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2048 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302049 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002050 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302051 {
Olli Etuahof119a262016-08-19 15:54:22 +03002052 case EOpNegative:
2053 switch (getType().getBasicType())
2054 {
2055 case EbtFloat:
2056 resultArray[i].setFConst(-operandArray[i].getFConst());
2057 break;
2058 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002059 if (operandArray[i] == std::numeric_limits<int>::min())
2060 {
2061 // The minimum representable integer doesn't have a positive
2062 // counterpart, rather the negation overflows and in ESSL is supposed to
2063 // wrap back to the minimum representable integer. Make sure that we
2064 // don't actually let the negation overflow, which has undefined
2065 // behavior in C++.
2066 resultArray[i].setIConst(std::numeric_limits<int>::min());
2067 }
2068 else
2069 {
2070 resultArray[i].setIConst(-operandArray[i].getIConst());
2071 }
Olli Etuahof119a262016-08-19 15:54:22 +03002072 break;
2073 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002074 if (operandArray[i] == 0x80000000u)
2075 {
2076 resultArray[i].setUConst(0x80000000u);
2077 }
2078 else
2079 {
2080 resultArray[i].setUConst(static_cast<unsigned int>(
2081 -static_cast<int>(operandArray[i].getUConst())));
2082 }
Olli Etuahof119a262016-08-19 15:54:22 +03002083 break;
2084 default:
2085 UNREACHABLE();
2086 return nullptr;
2087 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302088 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302089
Olli Etuahof119a262016-08-19 15:54:22 +03002090 case EOpPositive:
2091 switch (getType().getBasicType())
2092 {
2093 case EbtFloat:
2094 resultArray[i].setFConst(operandArray[i].getFConst());
2095 break;
2096 case EbtInt:
2097 resultArray[i].setIConst(operandArray[i].getIConst());
2098 break;
2099 case EbtUInt:
2100 resultArray[i].setUConst(static_cast<unsigned int>(
2101 static_cast<int>(operandArray[i].getUConst())));
2102 break;
2103 default:
2104 UNREACHABLE();
2105 return nullptr;
2106 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302107 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302108
Olli Etuahof119a262016-08-19 15:54:22 +03002109 case EOpLogicalNot:
2110 switch (getType().getBasicType())
2111 {
2112 case EbtBool:
2113 resultArray[i].setBConst(!operandArray[i].getBConst());
2114 break;
2115 default:
2116 UNREACHABLE();
2117 return nullptr;
2118 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302119 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302120
Olli Etuahof119a262016-08-19 15:54:22 +03002121 case EOpBitwiseNot:
2122 switch (getType().getBasicType())
2123 {
2124 case EbtInt:
2125 resultArray[i].setIConst(~operandArray[i].getIConst());
2126 break;
2127 case EbtUInt:
2128 resultArray[i].setUConst(~operandArray[i].getUConst());
2129 break;
2130 default:
2131 UNREACHABLE();
2132 return nullptr;
2133 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302134 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302135
Olli Etuahof119a262016-08-19 15:54:22 +03002136 case EOpRadians:
2137 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302138 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2139 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302140
Olli Etuahof119a262016-08-19 15:54:22 +03002141 case EOpDegrees:
2142 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302143 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2144 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302145
Olli Etuahof119a262016-08-19 15:54:22 +03002146 case EOpSin:
2147 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302148 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302149
Olli Etuahof119a262016-08-19 15:54:22 +03002150 case EOpCos:
2151 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2152 break;
2153
2154 case EOpTan:
2155 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2156 break;
2157
2158 case EOpAsin:
2159 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2160 // 0.
2161 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2162 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2163 diagnostics, &resultArray[i]);
2164 else
2165 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2166 break;
2167
2168 case EOpAcos:
2169 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2170 // 0.
2171 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2172 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2173 diagnostics, &resultArray[i]);
2174 else
2175 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2176 break;
2177
2178 case EOpAtan:
2179 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2180 break;
2181
2182 case EOpSinh:
2183 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2184 break;
2185
2186 case EOpCosh:
2187 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2188 break;
2189
2190 case EOpTanh:
2191 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2192 break;
2193
2194 case EOpAsinh:
2195 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2196 break;
2197
2198 case EOpAcosh:
2199 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2200 if (operandArray[i].getFConst() < 1.0f)
2201 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2202 diagnostics, &resultArray[i]);
2203 else
2204 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2205 break;
2206
2207 case EOpAtanh:
2208 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2209 // 0.
2210 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2211 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2212 diagnostics, &resultArray[i]);
2213 else
2214 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2215 break;
2216
2217 case EOpAbs:
2218 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302219 {
Olli Etuahof119a262016-08-19 15:54:22 +03002220 case EbtFloat:
2221 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2222 break;
2223 case EbtInt:
2224 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2225 break;
2226 default:
2227 UNREACHABLE();
2228 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302229 }
2230 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002231
2232 case EOpSign:
2233 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302234 {
Olli Etuahof119a262016-08-19 15:54:22 +03002235 case EbtFloat:
2236 {
2237 float fConst = operandArray[i].getFConst();
2238 float fResult = 0.0f;
2239 if (fConst > 0.0f)
2240 fResult = 1.0f;
2241 else if (fConst < 0.0f)
2242 fResult = -1.0f;
2243 resultArray[i].setFConst(fResult);
2244 break;
2245 }
2246 case EbtInt:
2247 {
2248 int iConst = operandArray[i].getIConst();
2249 int iResult = 0;
2250 if (iConst > 0)
2251 iResult = 1;
2252 else if (iConst < 0)
2253 iResult = -1;
2254 resultArray[i].setIConst(iResult);
2255 break;
2256 }
2257 default:
2258 UNREACHABLE();
2259 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302260 }
2261 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302262
Olli Etuahof119a262016-08-19 15:54:22 +03002263 case EOpFloor:
2264 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2265 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302266
Olli Etuahof119a262016-08-19 15:54:22 +03002267 case EOpTrunc:
2268 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2269 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302270
Olli Etuahof119a262016-08-19 15:54:22 +03002271 case EOpRound:
2272 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2273 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302274
Olli Etuahof119a262016-08-19 15:54:22 +03002275 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302276 {
Olli Etuahof119a262016-08-19 15:54:22 +03002277 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302278 float x = operandArray[i].getFConst();
2279 float result;
2280 float fractPart = modff(x, &result);
2281 if (fabsf(fractPart) == 0.5f)
2282 result = 2.0f * roundf(x / 2.0f);
2283 else
2284 result = roundf(x);
2285 resultArray[i].setFConst(result);
2286 break;
2287 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302288
Olli Etuahof119a262016-08-19 15:54:22 +03002289 case EOpCeil:
2290 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2291 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302292
Olli Etuahof119a262016-08-19 15:54:22 +03002293 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302294 {
Olli Etuahof119a262016-08-19 15:54:22 +03002295 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302296 float x = operandArray[i].getFConst();
2297 resultArray[i].setFConst(x - floorf(x));
2298 break;
2299 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302300
Olli Etuahof119a262016-08-19 15:54:22 +03002301 case EOpIsNan:
2302 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302303 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2304 break;
Arun Patole551279e2015-07-07 18:18:23 +05302305
Olli Etuahof119a262016-08-19 15:54:22 +03002306 case EOpIsInf:
2307 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302308 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2309 break;
Arun Patole551279e2015-07-07 18:18:23 +05302310
Olli Etuahof119a262016-08-19 15:54:22 +03002311 case EOpFloatBitsToInt:
2312 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302313 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2314 break;
Arun Patole551279e2015-07-07 18:18:23 +05302315
Olli Etuahof119a262016-08-19 15:54:22 +03002316 case EOpFloatBitsToUint:
2317 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302318 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2319 break;
Arun Patole551279e2015-07-07 18:18:23 +05302320
Olli Etuahof119a262016-08-19 15:54:22 +03002321 case EOpIntBitsToFloat:
2322 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302323 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2324 break;
Arun Patole551279e2015-07-07 18:18:23 +05302325
Olli Etuahof119a262016-08-19 15:54:22 +03002326 case EOpUintBitsToFloat:
2327 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302328 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2329 break;
Arun Patole551279e2015-07-07 18:18:23 +05302330
Olli Etuahof119a262016-08-19 15:54:22 +03002331 case EOpExp:
2332 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2333 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302334
Olli Etuahof119a262016-08-19 15:54:22 +03002335 case EOpLog:
2336 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2337 if (operandArray[i].getFConst() <= 0.0f)
2338 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2339 diagnostics, &resultArray[i]);
2340 else
2341 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2342 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302343
Olli Etuahof119a262016-08-19 15:54:22 +03002344 case EOpExp2:
2345 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2346 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302347
Olli Etuahof119a262016-08-19 15:54:22 +03002348 case EOpLog2:
2349 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2350 // And log2f is not available on some plarforms like old android, so just using
2351 // log(x)/log(2) here.
2352 if (operandArray[i].getFConst() <= 0.0f)
2353 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2354 diagnostics, &resultArray[i]);
2355 else
2356 {
2357 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2358 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2359 }
2360 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302361
Olli Etuahof119a262016-08-19 15:54:22 +03002362 case EOpSqrt:
2363 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2364 if (operandArray[i].getFConst() < 0.0f)
2365 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2366 diagnostics, &resultArray[i]);
2367 else
2368 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2369 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302370
Olli Etuahof119a262016-08-19 15:54:22 +03002371 case EOpInverseSqrt:
2372 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2373 // so getting the square root first using builtin function sqrt() and then taking
2374 // its inverse.
2375 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2376 // result to 0.
2377 if (operandArray[i].getFConst() <= 0.0f)
2378 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2379 diagnostics, &resultArray[i]);
2380 else
2381 {
2382 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2383 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2384 }
2385 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302386
Olli Etuahod68924e2017-01-02 17:34:40 +00002387 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002388 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302389 resultArray[i].setBConst(!operandArray[i].getBConst());
2390 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302391
Olli Etuahof119a262016-08-19 15:54:22 +03002392 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302393 {
Olli Etuahof119a262016-08-19 15:54:22 +03002394 ASSERT(getType().getBasicType() == EbtFloat);
2395 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302396 float length = VectorLength(operandArray, objectSize);
2397 if (length)
2398 resultArray[i].setFConst(x / length);
2399 else
Olli Etuahof119a262016-08-19 15:54:22 +03002400 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2401 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302402 break;
2403 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002404 case EOpBitfieldReverse:
2405 {
2406 uint32_t value;
2407 if (getType().getBasicType() == EbtInt)
2408 {
2409 value = static_cast<uint32_t>(operandArray[i].getIConst());
2410 }
2411 else
2412 {
2413 ASSERT(getType().getBasicType() == EbtUInt);
2414 value = operandArray[i].getUConst();
2415 }
2416 uint32_t result = gl::BitfieldReverse(value);
2417 if (getType().getBasicType() == EbtInt)
2418 {
2419 resultArray[i].setIConst(static_cast<int32_t>(result));
2420 }
2421 else
2422 {
2423 resultArray[i].setUConst(result);
2424 }
2425 break;
2426 }
2427 case EOpBitCount:
2428 {
2429 uint32_t value;
2430 if (getType().getBasicType() == EbtInt)
2431 {
2432 value = static_cast<uint32_t>(operandArray[i].getIConst());
2433 }
2434 else
2435 {
2436 ASSERT(getType().getBasicType() == EbtUInt);
2437 value = operandArray[i].getUConst();
2438 }
2439 int result = gl::BitCount(value);
2440 resultArray[i].setIConst(result);
2441 break;
2442 }
2443 case EOpFindLSB:
2444 {
2445 uint32_t value;
2446 if (getType().getBasicType() == EbtInt)
2447 {
2448 value = static_cast<uint32_t>(operandArray[i].getIConst());
2449 }
2450 else
2451 {
2452 ASSERT(getType().getBasicType() == EbtUInt);
2453 value = operandArray[i].getUConst();
2454 }
2455 resultArray[i].setIConst(gl::FindLSB(value));
2456 break;
2457 }
2458 case EOpFindMSB:
2459 {
2460 uint32_t value;
2461 if (getType().getBasicType() == EbtInt)
2462 {
2463 int intValue = operandArray[i].getIConst();
2464 value = static_cast<uint32_t>(intValue);
2465 if (intValue < 0)
2466 {
2467 // Look for zero instead of one in value. This also handles the intValue ==
2468 // -1 special case, where the return value needs to be -1.
2469 value = ~value;
2470 }
2471 }
2472 else
2473 {
2474 ASSERT(getType().getBasicType() == EbtUInt);
2475 value = operandArray[i].getUConst();
2476 }
2477 resultArray[i].setIConst(gl::FindMSB(value));
2478 break;
2479 }
Olli Etuahof119a262016-08-19 15:54:22 +03002480 case EOpDFdx:
2481 case EOpDFdy:
2482 case EOpFwidth:
2483 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302484 // Derivatives of constant arguments should be 0.
2485 resultArray[i].setFConst(0.0f);
2486 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302487
Olli Etuahof119a262016-08-19 15:54:22 +03002488 default:
2489 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302490 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302491 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002492
Arun Patoleab2b9a22015-07-06 18:27:56 +05302493 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002494}
2495
Olli Etuahof119a262016-08-19 15:54:22 +03002496void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2497 FloatTypeUnaryFunc builtinFunc,
2498 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302499{
2500 ASSERT(builtinFunc);
2501
Olli Etuahof119a262016-08-19 15:54:22 +03002502 ASSERT(getType().getBasicType() == EbtFloat);
2503 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302504}
2505
Jamie Madillb1a85f42014-08-19 15:23:24 -04002506// static
Olli Etuahof119a262016-08-19 15:54:22 +03002507TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002508{
2509 ASSERT(aggregate->getSequence()->size() > 0u);
2510 size_t resultSize = aggregate->getType().getObjectSize();
2511 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2512 TBasicType basicType = aggregate->getBasicType();
2513
2514 size_t resultIndex = 0u;
2515
2516 if (aggregate->getSequence()->size() == 1u)
2517 {
2518 TIntermNode *argument = aggregate->getSequence()->front();
2519 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2520 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2521 // Check the special case of constructing a matrix diagonal from a single scalar,
2522 // or a vector from a single scalar.
2523 if (argumentConstant->getType().getObjectSize() == 1u)
2524 {
2525 if (aggregate->isMatrix())
2526 {
2527 int resultCols = aggregate->getType().getCols();
2528 int resultRows = aggregate->getType().getRows();
2529 for (int col = 0; col < resultCols; ++col)
2530 {
2531 for (int row = 0; row < resultRows; ++row)
2532 {
2533 if (col == row)
2534 {
2535 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2536 }
2537 else
2538 {
2539 resultArray[resultIndex].setFConst(0.0f);
2540 }
2541 ++resultIndex;
2542 }
2543 }
2544 }
2545 else
2546 {
2547 while (resultIndex < resultSize)
2548 {
2549 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2550 ++resultIndex;
2551 }
2552 }
2553 ASSERT(resultIndex == resultSize);
2554 return resultArray;
2555 }
2556 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2557 {
2558 // The special case of constructing a matrix from a matrix.
2559 int argumentCols = argumentConstant->getType().getCols();
2560 int argumentRows = argumentConstant->getType().getRows();
2561 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002562 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002563 for (int col = 0; col < resultCols; ++col)
2564 {
2565 for (int row = 0; row < resultRows; ++row)
2566 {
2567 if (col < argumentCols && row < argumentRows)
2568 {
2569 resultArray[resultIndex].cast(basicType,
2570 argumentUnionArray[col * argumentRows + row]);
2571 }
2572 else if (col == row)
2573 {
2574 resultArray[resultIndex].setFConst(1.0f);
2575 }
2576 else
2577 {
2578 resultArray[resultIndex].setFConst(0.0f);
2579 }
2580 ++resultIndex;
2581 }
2582 }
2583 ASSERT(resultIndex == resultSize);
2584 return resultArray;
2585 }
2586 }
2587
2588 for (TIntermNode *&argument : *aggregate->getSequence())
2589 {
2590 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2591 size_t argumentSize = argumentConstant->getType().getObjectSize();
2592 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2593 for (size_t i = 0u; i < argumentSize; ++i)
2594 {
2595 if (resultIndex >= resultSize)
2596 break;
2597 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2598 ++resultIndex;
2599 }
2600 }
2601 ASSERT(resultIndex == resultSize);
2602 return resultArray;
2603}
2604
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002605bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2606{
2607 switch (op)
2608 {
2609 case EOpAtan:
2610 case EOpPow:
2611 case EOpMod:
2612 case EOpMin:
2613 case EOpMax:
2614 case EOpClamp:
2615 case EOpMix:
2616 case EOpStep:
2617 case EOpSmoothStep:
2618 case EOpLdexp:
2619 case EOpMulMatrixComponentWise:
2620 case EOpOuterProduct:
2621 case EOpEqualComponentWise:
2622 case EOpNotEqualComponentWise:
2623 case EOpLessThanComponentWise:
2624 case EOpLessThanEqualComponentWise:
2625 case EOpGreaterThanComponentWise:
2626 case EOpGreaterThanEqualComponentWise:
2627 case EOpDistance:
2628 case EOpDot:
2629 case EOpCross:
2630 case EOpFaceforward:
2631 case EOpReflect:
2632 case EOpRefract:
2633 case EOpBitfieldExtract:
2634 case EOpBitfieldInsert:
2635 return true;
2636 default:
2637 return false;
2638 }
2639}
2640
Olli Etuaho1d122782015-11-06 15:35:17 +02002641// static
Olli Etuahof119a262016-08-19 15:54:22 +03002642TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2643 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302644{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002645 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002646 TIntermSequence *arguments = aggregate->getSequence();
2647 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2648 std::vector<const TConstantUnion *> unionArrays(argsCount);
2649 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002650 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302651 TBasicType basicType = EbtVoid;
2652 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002653 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302654 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002655 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2656 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302657
2658 if (i == 0)
2659 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002660 basicType = argConstant->getType().getBasicType();
2661 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302662 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002663 unionArrays[i] = argConstant->getUnionArrayPointer();
2664 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002665 if (objectSizes[i] > maxObjectSize)
2666 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302667 }
2668
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002669 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302670 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002671 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302672 if (objectSizes[i] != maxObjectSize)
2673 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2674 }
Arun Patole274f0702015-05-05 13:33:30 +05302675
Olli Etuahob43846e2015-06-02 18:18:57 +03002676 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002677
2678 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302679 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002680 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302681 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002682 ASSERT(basicType == EbtFloat);
2683 resultArray = new TConstantUnion[maxObjectSize];
2684 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302685 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002686 float y = unionArrays[0][i].getFConst();
2687 float x = unionArrays[1][i].getFConst();
2688 // Results are undefined if x and y are both 0.
2689 if (x == 0.0f && y == 0.0f)
2690 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2691 else
2692 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302693 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002694 break;
2695 }
Arun Patolebf790422015-05-18 17:53:04 +05302696
Olli Etuaho51182ab2017-01-22 00:12:29 +00002697 case EOpPow:
2698 {
2699 ASSERT(basicType == EbtFloat);
2700 resultArray = new TConstantUnion[maxObjectSize];
2701 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302702 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002703 float x = unionArrays[0][i].getFConst();
2704 float y = unionArrays[1][i].getFConst();
2705 // Results are undefined if x < 0.
2706 // Results are undefined if x = 0 and y <= 0.
2707 if (x < 0.0f)
2708 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2709 else if (x == 0.0f && y <= 0.0f)
2710 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2711 else
2712 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302713 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002714 break;
2715 }
Arun Patolebf790422015-05-18 17:53:04 +05302716
Olli Etuaho51182ab2017-01-22 00:12:29 +00002717 case EOpMod:
2718 {
2719 ASSERT(basicType == EbtFloat);
2720 resultArray = new TConstantUnion[maxObjectSize];
2721 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302722 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002723 float x = unionArrays[0][i].getFConst();
2724 float y = unionArrays[1][i].getFConst();
2725 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302726 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002727 break;
2728 }
Arun Patolebf790422015-05-18 17:53:04 +05302729
Olli Etuaho51182ab2017-01-22 00:12:29 +00002730 case EOpMin:
2731 {
2732 resultArray = new TConstantUnion[maxObjectSize];
2733 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302734 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002735 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302736 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002737 case EbtFloat:
2738 resultArray[i].setFConst(
2739 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2740 break;
2741 case EbtInt:
2742 resultArray[i].setIConst(
2743 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2744 break;
2745 case EbtUInt:
2746 resultArray[i].setUConst(
2747 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2748 break;
2749 default:
2750 UNREACHABLE();
2751 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302752 }
2753 }
2754 break;
Arun Patole274f0702015-05-05 13:33:30 +05302755 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002756
2757 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302758 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002759 resultArray = new TConstantUnion[maxObjectSize];
2760 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302761 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002762 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302763 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002764 case EbtFloat:
2765 resultArray[i].setFConst(
2766 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2767 break;
2768 case EbtInt:
2769 resultArray[i].setIConst(
2770 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2771 break;
2772 case EbtUInt:
2773 resultArray[i].setUConst(
2774 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2775 break;
2776 default:
2777 UNREACHABLE();
2778 break;
Arun Patole274f0702015-05-05 13:33:30 +05302779 }
2780 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002781 break;
Arun Patole274f0702015-05-05 13:33:30 +05302782 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002783
2784 case EOpStep:
2785 {
2786 ASSERT(basicType == EbtFloat);
2787 resultArray = new TConstantUnion[maxObjectSize];
2788 for (size_t i = 0; i < maxObjectSize; i++)
2789 resultArray[i].setFConst(
2790 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2791 break;
2792 }
2793
2794 case EOpLessThanComponentWise:
2795 {
2796 resultArray = new TConstantUnion[maxObjectSize];
2797 for (size_t i = 0; i < maxObjectSize; i++)
2798 {
2799 switch (basicType)
2800 {
2801 case EbtFloat:
2802 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2803 unionArrays[1][i].getFConst());
2804 break;
2805 case EbtInt:
2806 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2807 unionArrays[1][i].getIConst());
2808 break;
2809 case EbtUInt:
2810 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2811 unionArrays[1][i].getUConst());
2812 break;
2813 default:
2814 UNREACHABLE();
2815 break;
2816 }
2817 }
2818 break;
2819 }
2820
2821 case EOpLessThanEqualComponentWise:
2822 {
2823 resultArray = new TConstantUnion[maxObjectSize];
2824 for (size_t i = 0; i < maxObjectSize; i++)
2825 {
2826 switch (basicType)
2827 {
2828 case EbtFloat:
2829 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2830 unionArrays[1][i].getFConst());
2831 break;
2832 case EbtInt:
2833 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2834 unionArrays[1][i].getIConst());
2835 break;
2836 case EbtUInt:
2837 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2838 unionArrays[1][i].getUConst());
2839 break;
2840 default:
2841 UNREACHABLE();
2842 break;
2843 }
2844 }
2845 break;
2846 }
2847
2848 case EOpGreaterThanComponentWise:
2849 {
2850 resultArray = new TConstantUnion[maxObjectSize];
2851 for (size_t i = 0; i < maxObjectSize; i++)
2852 {
2853 switch (basicType)
2854 {
2855 case EbtFloat:
2856 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2857 unionArrays[1][i].getFConst());
2858 break;
2859 case EbtInt:
2860 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2861 unionArrays[1][i].getIConst());
2862 break;
2863 case EbtUInt:
2864 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2865 unionArrays[1][i].getUConst());
2866 break;
2867 default:
2868 UNREACHABLE();
2869 break;
2870 }
2871 }
2872 break;
2873 }
2874 case EOpGreaterThanEqualComponentWise:
2875 {
2876 resultArray = new TConstantUnion[maxObjectSize];
2877 for (size_t i = 0; i < maxObjectSize; i++)
2878 {
2879 switch (basicType)
2880 {
2881 case EbtFloat:
2882 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2883 unionArrays[1][i].getFConst());
2884 break;
2885 case EbtInt:
2886 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2887 unionArrays[1][i].getIConst());
2888 break;
2889 case EbtUInt:
2890 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2891 unionArrays[1][i].getUConst());
2892 break;
2893 default:
2894 UNREACHABLE();
2895 break;
2896 }
2897 }
2898 }
2899 break;
2900
2901 case EOpEqualComponentWise:
2902 {
2903 resultArray = new TConstantUnion[maxObjectSize];
2904 for (size_t i = 0; i < maxObjectSize; i++)
2905 {
2906 switch (basicType)
2907 {
2908 case EbtFloat:
2909 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2910 unionArrays[1][i].getFConst());
2911 break;
2912 case EbtInt:
2913 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2914 unionArrays[1][i].getIConst());
2915 break;
2916 case EbtUInt:
2917 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2918 unionArrays[1][i].getUConst());
2919 break;
2920 case EbtBool:
2921 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2922 unionArrays[1][i].getBConst());
2923 break;
2924 default:
2925 UNREACHABLE();
2926 break;
2927 }
2928 }
2929 break;
2930 }
2931
2932 case EOpNotEqualComponentWise:
2933 {
2934 resultArray = new TConstantUnion[maxObjectSize];
2935 for (size_t i = 0; i < maxObjectSize; i++)
2936 {
2937 switch (basicType)
2938 {
2939 case EbtFloat:
2940 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2941 unionArrays[1][i].getFConst());
2942 break;
2943 case EbtInt:
2944 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2945 unionArrays[1][i].getIConst());
2946 break;
2947 case EbtUInt:
2948 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2949 unionArrays[1][i].getUConst());
2950 break;
2951 case EbtBool:
2952 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2953 unionArrays[1][i].getBConst());
2954 break;
2955 default:
2956 UNREACHABLE();
2957 break;
2958 }
2959 }
2960 break;
2961 }
2962
2963 case EOpDistance:
2964 {
2965 ASSERT(basicType == EbtFloat);
2966 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2967 resultArray = new TConstantUnion();
2968 for (size_t i = 0; i < maxObjectSize; i++)
2969 {
2970 float x = unionArrays[0][i].getFConst();
2971 float y = unionArrays[1][i].getFConst();
2972 distanceArray[i].setFConst(x - y);
2973 }
2974 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2975 break;
2976 }
2977
2978 case EOpDot:
2979 ASSERT(basicType == EbtFloat);
2980 resultArray = new TConstantUnion();
2981 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2982 break;
2983
2984 case EOpCross:
2985 {
2986 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2987 resultArray = new TConstantUnion[maxObjectSize];
2988 float x0 = unionArrays[0][0].getFConst();
2989 float x1 = unionArrays[0][1].getFConst();
2990 float x2 = unionArrays[0][2].getFConst();
2991 float y0 = unionArrays[1][0].getFConst();
2992 float y1 = unionArrays[1][1].getFConst();
2993 float y2 = unionArrays[1][2].getFConst();
2994 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2995 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2996 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2997 break;
2998 }
2999
3000 case EOpReflect:
3001 {
3002 ASSERT(basicType == EbtFloat);
3003 // genType reflect (genType I, genType N) :
3004 // For the incident vector I and surface orientation N, returns the reflection
3005 // direction:
3006 // I - 2 * dot(N, I) * N.
3007 resultArray = new TConstantUnion[maxObjectSize];
3008 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3009 for (size_t i = 0; i < maxObjectSize; i++)
3010 {
3011 float result = unionArrays[0][i].getFConst() -
3012 2.0f * dotProduct * unionArrays[1][i].getFConst();
3013 resultArray[i].setFConst(result);
3014 }
3015 break;
3016 }
3017
3018 case EOpMulMatrixComponentWise:
3019 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003020 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3021 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003022 // Perform component-wise matrix multiplication.
3023 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003024 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003025 angle::Matrix<float> result =
3026 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3027 SetUnionArrayFromMatrix(result, resultArray);
3028 break;
3029 }
3030
3031 case EOpOuterProduct:
3032 {
3033 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003034 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3035 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003036 resultArray = new TConstantUnion[numRows * numCols];
3037 angle::Matrix<float> result =
3038 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3039 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3040 SetUnionArrayFromMatrix(result, resultArray);
3041 break;
3042 }
3043
3044 case EOpClamp:
3045 {
3046 resultArray = new TConstantUnion[maxObjectSize];
3047 for (size_t i = 0; i < maxObjectSize; i++)
3048 {
3049 switch (basicType)
3050 {
3051 case EbtFloat:
3052 {
3053 float x = unionArrays[0][i].getFConst();
3054 float min = unionArrays[1][i].getFConst();
3055 float max = unionArrays[2][i].getFConst();
3056 // Results are undefined if min > max.
3057 if (min > max)
3058 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3059 &resultArray[i]);
3060 else
3061 resultArray[i].setFConst(gl::clamp(x, min, max));
3062 break;
3063 }
3064
3065 case EbtInt:
3066 {
3067 int x = unionArrays[0][i].getIConst();
3068 int min = unionArrays[1][i].getIConst();
3069 int max = unionArrays[2][i].getIConst();
3070 // Results are undefined if min > max.
3071 if (min > max)
3072 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3073 &resultArray[i]);
3074 else
3075 resultArray[i].setIConst(gl::clamp(x, min, max));
3076 break;
3077 }
3078 case EbtUInt:
3079 {
3080 unsigned int x = unionArrays[0][i].getUConst();
3081 unsigned int min = unionArrays[1][i].getUConst();
3082 unsigned int max = unionArrays[2][i].getUConst();
3083 // Results are undefined if min > max.
3084 if (min > max)
3085 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3086 &resultArray[i]);
3087 else
3088 resultArray[i].setUConst(gl::clamp(x, min, max));
3089 break;
3090 }
3091 default:
3092 UNREACHABLE();
3093 break;
3094 }
3095 }
3096 break;
3097 }
3098
3099 case EOpMix:
3100 {
3101 ASSERT(basicType == EbtFloat);
3102 resultArray = new TConstantUnion[maxObjectSize];
3103 for (size_t i = 0; i < maxObjectSize; i++)
3104 {
3105 float x = unionArrays[0][i].getFConst();
3106 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003107 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003108 if (type == EbtFloat)
3109 {
3110 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3111 float a = unionArrays[2][i].getFConst();
3112 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3113 }
3114 else // 3rd parameter is EbtBool
3115 {
3116 ASSERT(type == EbtBool);
3117 // Selects which vector each returned component comes from.
3118 // For a component of a that is false, the corresponding component of x is
3119 // returned.
3120 // For a component of a that is true, the corresponding component of y is
3121 // returned.
3122 bool a = unionArrays[2][i].getBConst();
3123 resultArray[i].setFConst(a ? y : x);
3124 }
3125 }
3126 break;
3127 }
3128
3129 case EOpSmoothStep:
3130 {
3131 ASSERT(basicType == EbtFloat);
3132 resultArray = new TConstantUnion[maxObjectSize];
3133 for (size_t i = 0; i < maxObjectSize; i++)
3134 {
3135 float edge0 = unionArrays[0][i].getFConst();
3136 float edge1 = unionArrays[1][i].getFConst();
3137 float x = unionArrays[2][i].getFConst();
3138 // Results are undefined if edge0 >= edge1.
3139 if (edge0 >= edge1)
3140 {
3141 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3142 }
3143 else
3144 {
3145 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3146 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3147 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3148 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3149 }
3150 }
3151 break;
3152 }
3153
Olli Etuaho74da73f2017-02-01 15:37:48 +00003154 case EOpLdexp:
3155 {
3156 resultArray = new TConstantUnion[maxObjectSize];
3157 for (size_t i = 0; i < maxObjectSize; i++)
3158 {
3159 float x = unionArrays[0][i].getFConst();
3160 int exp = unionArrays[1][i].getIConst();
3161 if (exp > 128)
3162 {
3163 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3164 }
3165 else
3166 {
3167 resultArray[i].setFConst(gl::Ldexp(x, exp));
3168 }
3169 }
3170 break;
3171 }
3172
Jamie Madille72595b2017-06-06 15:12:26 -04003173 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003174 {
3175 ASSERT(basicType == EbtFloat);
3176 // genType faceforward(genType N, genType I, genType Nref) :
3177 // If dot(Nref, I) < 0 return N, otherwise return -N.
3178 resultArray = new TConstantUnion[maxObjectSize];
3179 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3180 for (size_t i = 0; i < maxObjectSize; i++)
3181 {
3182 if (dotProduct < 0)
3183 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3184 else
3185 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3186 }
3187 break;
3188 }
3189
3190 case EOpRefract:
3191 {
3192 ASSERT(basicType == EbtFloat);
3193 // genType refract(genType I, genType N, float eta) :
3194 // For the incident vector I and surface normal N, and the ratio of indices of
3195 // refraction eta,
3196 // return the refraction vector. The result is computed by
3197 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3198 // if (k < 0.0)
3199 // return genType(0.0)
3200 // else
3201 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3202 resultArray = new TConstantUnion[maxObjectSize];
3203 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3204 for (size_t i = 0; i < maxObjectSize; i++)
3205 {
3206 float eta = unionArrays[2][i].getFConst();
3207 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3208 if (k < 0.0f)
3209 resultArray[i].setFConst(0.0f);
3210 else
3211 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3212 (eta * dotProduct + sqrtf(k)) *
3213 unionArrays[1][i].getFConst());
3214 }
3215 break;
3216 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003217 case EOpBitfieldExtract:
3218 {
3219 resultArray = new TConstantUnion[maxObjectSize];
3220 for (size_t i = 0; i < maxObjectSize; ++i)
3221 {
3222 int offset = unionArrays[1][0].getIConst();
3223 int bits = unionArrays[2][0].getIConst();
3224 if (bits == 0)
3225 {
3226 if (aggregate->getBasicType() == EbtInt)
3227 {
3228 resultArray[i].setIConst(0);
3229 }
3230 else
3231 {
3232 ASSERT(aggregate->getBasicType() == EbtUInt);
3233 resultArray[i].setUConst(0);
3234 }
3235 }
3236 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3237 {
3238 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3239 &resultArray[i]);
3240 }
3241 else
3242 {
3243 // bits can be 32 here, so we need to avoid bit shift overflow.
3244 uint32_t maskMsb = 1u << (bits - 1);
3245 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3246 if (aggregate->getBasicType() == EbtInt)
3247 {
3248 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3249 uint32_t resultUnsigned = (value & mask) >> offset;
3250 if ((resultUnsigned & maskMsb) != 0)
3251 {
3252 // The most significant bits (from bits+1 to the most significant bit)
3253 // should be set to 1.
3254 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3255 resultUnsigned |= higherBitsMask;
3256 }
3257 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3258 }
3259 else
3260 {
3261 ASSERT(aggregate->getBasicType() == EbtUInt);
3262 uint32_t value = unionArrays[0][i].getUConst();
3263 resultArray[i].setUConst((value & mask) >> offset);
3264 }
3265 }
3266 }
3267 break;
3268 }
3269 case EOpBitfieldInsert:
3270 {
3271 resultArray = new TConstantUnion[maxObjectSize];
3272 for (size_t i = 0; i < maxObjectSize; ++i)
3273 {
3274 int offset = unionArrays[2][0].getIConst();
3275 int bits = unionArrays[3][0].getIConst();
3276 if (bits == 0)
3277 {
3278 if (aggregate->getBasicType() == EbtInt)
3279 {
3280 int32_t base = unionArrays[0][i].getIConst();
3281 resultArray[i].setIConst(base);
3282 }
3283 else
3284 {
3285 ASSERT(aggregate->getBasicType() == EbtUInt);
3286 uint32_t base = unionArrays[0][i].getUConst();
3287 resultArray[i].setUConst(base);
3288 }
3289 }
3290 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3291 {
3292 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3293 &resultArray[i]);
3294 }
3295 else
3296 {
3297 // bits can be 32 here, so we need to avoid bit shift overflow.
3298 uint32_t maskMsb = 1u << (bits - 1);
3299 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3300 uint32_t baseMask = ~insertMask;
3301 if (aggregate->getBasicType() == EbtInt)
3302 {
3303 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3304 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3305 uint32_t resultUnsigned =
3306 (base & baseMask) | ((insert << offset) & insertMask);
3307 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3308 }
3309 else
3310 {
3311 ASSERT(aggregate->getBasicType() == EbtUInt);
3312 uint32_t base = unionArrays[0][i].getUConst();
3313 uint32_t insert = unionArrays[1][i].getUConst();
3314 resultArray[i].setUConst((base & baseMask) |
3315 ((insert << offset) & insertMask));
3316 }
3317 }
3318 }
3319 break;
3320 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003321
3322 default:
3323 UNREACHABLE();
3324 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303325 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003326 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303327}
3328
Jamie Madill45bcc782016-11-07 13:58:48 -05003329} // namespace sh