blob: bf2b8c7884bf6443818922b421c8fb9e6a27d433 [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 Etuaho13389b62016-10-16 11:48:18 +0100483 // Declaration nodes with no children can appear if all the declarators just added constants to
484 // the symbol table instead of generating code. They're no-ops so they aren't added to blocks.
485 if (statement != nullptr && (statement->getAsDeclarationNode() == nullptr ||
486 !statement->getAsDeclarationNode()->getSequence()->empty()))
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100487 {
488 mStatements.push_back(statement);
489 }
490}
491
Olli Etuaho16c745a2017-01-16 17:02:27 +0000492void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
493{
494 ASSERT(parameter != nullptr);
495 mParameters.push_back(parameter);
496}
497
Olli Etuaho13389b62016-10-16 11:48:18 +0100498void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
499{
500 ASSERT(declarator != nullptr);
501 ASSERT(declarator->getAsSymbolNode() != nullptr ||
502 (declarator->getAsBinaryNode() != nullptr &&
503 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
504 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300505 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100506 mDeclarators.push_back(declarator);
507}
508
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300509bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
510{
511 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
512 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
513 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
514 return false;
515}
516
Olli Etuaho57961272016-09-14 13:57:46 +0300517bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400518{
519 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100520 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
521 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400522 return false;
523}
524
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500525bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200526{
527 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100528 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200529 return false;
530}
531
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500532bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200533{
534 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
535 return false;
536}
537
Olli Etuahod7a25242015-08-18 13:49:45 +0300538TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
539{
540 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
541 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
542 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
543 mLine = node.mLine;
544}
545
Olli Etuahod4f4c112016-04-15 15:11:24 +0300546bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
547{
548 TIntermAggregate *constructor = getAsAggregate();
549 if (!constructor || !constructor->isConstructor())
550 {
551 return false;
552 }
553 for (TIntermNode *&node : *constructor->getSequence())
554 {
555 if (!node->getAsConstantUnion())
556 return false;
557 }
558 return true;
559}
560
Olli Etuahod7a25242015-08-18 13:49:45 +0300561TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
562{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200563 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300564}
565
Olli Etuahobd674552016-10-06 13:28:42 +0100566void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
567{
Olli Etuahoec9232b2017-03-27 17:01:37 +0300568 setName(function.getName());
Olli Etuahofe486322017-03-21 09:30:54 +0000569 setId(TSymbolUniqueId(function));
570}
571
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300572TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id)
573 : mId(new TSymbolUniqueId(id)), mKnownToNotHaveSideEffects(false)
Olli Etuahofe486322017-03-21 09:30:54 +0000574{
575}
576
577TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300578 : mName(info.mName), mId(nullptr), mKnownToNotHaveSideEffects(info.mKnownToNotHaveSideEffects)
Olli Etuahofe486322017-03-21 09:30:54 +0000579{
580 if (info.mId)
581 {
582 mId = new TSymbolUniqueId(*info.mId);
583 }
584}
585
586TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
587{
588 mName = info.mName;
589 if (info.mId)
590 {
591 mId = new TSymbolUniqueId(*info.mId);
592 }
593 else
594 {
595 mId = nullptr;
596 }
597 return *this;
598}
599
600void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
601{
602 mId = new TSymbolUniqueId(id);
603}
604
605const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
606{
607 ASSERT(mId);
608 return *mId;
Olli Etuahobd674552016-10-06 13:28:42 +0100609}
610
Olli Etuahod7a25242015-08-18 13:49:45 +0300611TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
612 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300613 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100614 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
615 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300616{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800617 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300618 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800619 TIntermTyped *typedArg = arg->getAsTyped();
620 ASSERT(typedArg != nullptr);
621 TIntermTyped *argCopy = typedArg->deepCopy();
622 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300623 }
624}
625
Olli Etuahofe486322017-03-21 09:30:54 +0000626TIntermAggregate *TIntermAggregate::shallowCopy() const
627{
628 TIntermSequence *copySeq = new TIntermSequence();
629 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
630 TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq);
631 *copyNode->getFunctionSymbolInfo() = mFunctionInfo;
632 copyNode->setLine(mLine);
633 return copyNode;
634}
635
Olli Etuahob6fa0432016-09-28 16:28:05 +0100636TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
637{
638 TIntermTyped *operandCopy = node.mOperand->deepCopy();
639 ASSERT(operandCopy != nullptr);
640 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000641 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100642}
643
Olli Etuahod7a25242015-08-18 13:49:45 +0300644TIntermBinary::TIntermBinary(const TIntermBinary &node)
645 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
646{
647 TIntermTyped *leftCopy = node.mLeft->deepCopy();
648 TIntermTyped *rightCopy = node.mRight->deepCopy();
649 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
650 mLeft = leftCopy;
651 mRight = rightCopy;
652}
653
654TIntermUnary::TIntermUnary(const TIntermUnary &node)
655 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
656{
657 TIntermTyped *operandCopy = node.mOperand->deepCopy();
658 ASSERT(operandCopy != nullptr);
659 mOperand = operandCopy;
660}
661
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300662TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300663{
Olli Etuahod7a25242015-08-18 13:49:45 +0300664 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300665 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
666 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300667 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300668 mCondition = conditionCopy;
669 mTrueExpression = trueCopy;
670 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300671}
672
Jamie Madillb1a85f42014-08-19 15:23:24 -0400673bool TIntermOperator::isAssignment() const
674{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300675 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400676}
677
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300678bool TIntermOperator::isMultiplication() const
679{
680 switch (mOp)
681 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500682 case EOpMul:
683 case EOpMatrixTimesMatrix:
684 case EOpMatrixTimesVector:
685 case EOpMatrixTimesScalar:
686 case EOpVectorTimesMatrix:
687 case EOpVectorTimesScalar:
688 return true;
689 default:
690 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300691 }
692}
693
Jamie Madillb1a85f42014-08-19 15:23:24 -0400694bool TIntermOperator::isConstructor() const
695{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300696 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400697}
698
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800699bool TIntermOperator::isFunctionCall() const
700{
701 switch (mOp)
702 {
703 case EOpCallFunctionInAST:
704 case EOpCallBuiltInFunction:
705 case EOpCallInternalRawFunction:
706 return true;
707 default:
708 return false;
709 }
710}
711
Olli Etuaho1dded802016-08-18 18:13:13 +0300712TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
713{
714 if (left.isMatrix())
715 {
716 if (right.isMatrix())
717 {
718 return EOpMatrixTimesMatrix;
719 }
720 else
721 {
722 if (right.isVector())
723 {
724 return EOpMatrixTimesVector;
725 }
726 else
727 {
728 return EOpMatrixTimesScalar;
729 }
730 }
731 }
732 else
733 {
734 if (right.isMatrix())
735 {
736 if (left.isVector())
737 {
738 return EOpVectorTimesMatrix;
739 }
740 else
741 {
742 return EOpMatrixTimesScalar;
743 }
744 }
745 else
746 {
747 // Neither operand is a matrix.
748 if (left.isVector() == right.isVector())
749 {
750 // Leave as component product.
751 return EOpMul;
752 }
753 else
754 {
755 return EOpVectorTimesScalar;
756 }
757 }
758 }
759}
760
761TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
762{
763 if (left.isMatrix())
764 {
765 if (right.isMatrix())
766 {
767 return EOpMatrixTimesMatrixAssign;
768 }
769 else
770 {
771 // right should be scalar, but this may not be validated yet.
772 return EOpMatrixTimesScalarAssign;
773 }
774 }
775 else
776 {
777 if (right.isMatrix())
778 {
779 // Left should be a vector, but this may not be validated yet.
780 return EOpVectorTimesMatrixAssign;
781 }
782 else
783 {
784 // Neither operand is a matrix.
785 if (left.isVector() == right.isVector())
786 {
787 // Leave as component product.
788 return EOpMulAssign;
789 }
790 else
791 {
792 // left should be vector and right should be scalar, but this may not be validated
793 // yet.
794 return EOpVectorTimesScalarAssign;
795 }
796 }
797 }
798}
799
Jamie Madillb1a85f42014-08-19 15:23:24 -0400800//
801// Make sure the type of a unary operator is appropriate for its
802// combination of operation and operand type.
803//
Olli Etuahoa2234302016-08-31 12:05:39 +0300804void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400805{
Olli Etuahoa2234302016-08-31 12:05:39 +0300806 TQualifier resultQualifier = EvqTemporary;
807 if (mOperand->getQualifier() == EvqConst)
808 resultQualifier = EvqConst;
809
810 unsigned char operandPrimarySize =
811 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400812 switch (mOp)
813 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300814 case EOpFloatBitsToInt:
815 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
816 break;
817 case EOpFloatBitsToUint:
818 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
819 break;
820 case EOpIntBitsToFloat:
821 case EOpUintBitsToFloat:
822 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
823 break;
824 case EOpPackSnorm2x16:
825 case EOpPackUnorm2x16:
826 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800827 case EOpPackUnorm4x8:
828 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300829 setType(TType(EbtUInt, EbpHigh, resultQualifier));
830 break;
831 case EOpUnpackSnorm2x16:
832 case EOpUnpackUnorm2x16:
833 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
834 break;
835 case EOpUnpackHalf2x16:
836 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
837 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800838 case EOpUnpackUnorm4x8:
839 case EOpUnpackSnorm4x8:
840 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
841 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300842 case EOpAny:
843 case EOpAll:
844 setType(TType(EbtBool, EbpUndefined, resultQualifier));
845 break;
846 case EOpLength:
847 case EOpDeterminant:
848 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
849 break;
850 case EOpTranspose:
851 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
852 static_cast<unsigned char>(mOperand->getType().getRows()),
853 static_cast<unsigned char>(mOperand->getType().getCols())));
854 break;
855 case EOpIsInf:
856 case EOpIsNan:
857 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
858 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000859 case EOpBitfieldReverse:
860 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
861 break;
862 case EOpBitCount:
863 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
864 break;
865 case EOpFindLSB:
866 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
867 break;
868 case EOpFindMSB:
869 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
870 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300871 default:
872 setType(mOperand->getType());
873 mType.setQualifier(resultQualifier);
874 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400875 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300876}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400877
Olli Etuahob6fa0432016-09-28 16:28:05 +0100878TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
879 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
880 mOperand(operand),
881 mSwizzleOffsets(swizzleOffsets)
882{
883 ASSERT(mSwizzleOffsets.size() <= 4);
884 promote();
885}
886
Olli Etuahoa2234302016-08-31 12:05:39 +0300887TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
888 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
889{
890 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400891}
892
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300893TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
894 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
895{
896 promote();
897}
898
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000899TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
900 : TIntermNode(), mSymbol(symbol)
901{
902 ASSERT(symbol);
903 setLine(line);
904}
905
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300906TIntermTernary::TIntermTernary(TIntermTyped *cond,
907 TIntermTyped *trueExpression,
908 TIntermTyped *falseExpression)
909 : TIntermTyped(trueExpression->getType()),
910 mCondition(cond),
911 mTrueExpression(trueExpression),
912 mFalseExpression(falseExpression)
913{
914 getTypePointer()->setQualifier(
915 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
916}
917
Olli Etuaho81629262017-04-19 11:56:01 +0300918TIntermLoop::TIntermLoop(TLoopType type,
919 TIntermNode *init,
920 TIntermTyped *cond,
921 TIntermTyped *expr,
922 TIntermBlock *body)
923 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
924{
925 // Declaration nodes with no children can appear if all the declarators just added constants to
926 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
927 if (mInit && mInit->getAsDeclarationNode() &&
928 mInit->getAsDeclarationNode()->getSequence()->empty())
929 {
930 mInit = nullptr;
931 }
932}
933
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300934// static
935TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
936 TIntermTyped *trueExpression,
937 TIntermTyped *falseExpression)
938{
939 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
940 falseExpression->getQualifier() == EvqConst)
941 {
942 return EvqConst;
943 }
944 return EvqTemporary;
945}
946
Olli Etuahoeb7f90f2017-07-07 17:25:23 +0300947TIntermTyped *TIntermTernary::fold()
948{
949 if (mCondition->getAsConstantUnion())
950 {
951 if (mCondition->getAsConstantUnion()->getBConst(0))
952 {
953 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
954 return mTrueExpression;
955 }
956 else
957 {
958 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
959 return mFalseExpression;
960 }
961 }
962 return this;
963}
964
Olli Etuahob6fa0432016-09-28 16:28:05 +0100965void TIntermSwizzle::promote()
966{
967 TQualifier resultQualifier = EvqTemporary;
968 if (mOperand->getQualifier() == EvqConst)
969 resultQualifier = EvqConst;
970
971 auto numFields = mSwizzleOffsets.size();
972 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
973 static_cast<unsigned char>(numFields)));
974}
975
976bool TIntermSwizzle::hasDuplicateOffsets() const
977{
978 int offsetCount[4] = {0u, 0u, 0u, 0u};
979 for (const auto offset : mSwizzleOffsets)
980 {
981 offsetCount[offset]++;
982 if (offsetCount[offset] > 1)
983 {
984 return true;
985 }
986 }
987 return false;
988}
989
Olli Etuaho09b04a22016-12-15 13:30:26 +0000990bool TIntermSwizzle::offsetsMatch(int offset) const
991{
992 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
993}
994
Olli Etuahob6fa0432016-09-28 16:28:05 +0100995void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
996{
997 for (const int offset : mSwizzleOffsets)
998 {
999 switch (offset)
1000 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001001 case 0:
1002 *out << "x";
1003 break;
1004 case 1:
1005 *out << "y";
1006 break;
1007 case 2:
1008 *out << "z";
1009 break;
1010 case 3:
1011 *out << "w";
1012 break;
1013 default:
1014 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001015 }
1016 }
1017}
1018
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001019TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1020 const TIntermTyped *left,
1021 const TIntermTyped *right)
1022{
1023 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1024 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1025 right->getQualifier() != EvqConst)
1026 {
1027 return EvqTemporary;
1028 }
1029 return EvqConst;
1030}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001031
1032// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001033void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001034{
Olli Etuaho1dded802016-08-18 18:13:13 +03001035 ASSERT(!isMultiplication() ||
1036 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1037
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001038 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1039 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001040 if (mOp == EOpComma)
1041 {
1042 setType(mRight->getType());
1043 return;
1044 }
1045
Jamie Madillb1a85f42014-08-19 15:23:24 -04001046 // Base assumption: just make the type the same as the left
1047 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001048 setType(mLeft->getType());
1049
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001050 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001051 // Binary operations results in temporary variables unless both
1052 // operands are const.
1053 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1054 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001055 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001056 getTypePointer()->setQualifier(EvqTemporary);
1057 }
1058
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001059 // Handle indexing ops.
1060 switch (mOp)
1061 {
1062 case EOpIndexDirect:
1063 case EOpIndexIndirect:
1064 if (mLeft->isArray())
1065 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001066 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001067 }
1068 else if (mLeft->isMatrix())
1069 {
1070 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1071 static_cast<unsigned char>(mLeft->getRows())));
1072 }
1073 else if (mLeft->isVector())
1074 {
1075 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1076 }
1077 else
1078 {
1079 UNREACHABLE();
1080 }
1081 return;
1082 case EOpIndexDirectStruct:
1083 {
1084 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1085 const int i = mRight->getAsConstantUnion()->getIConst(0);
1086 setType(*fields[i]->type());
1087 getTypePointer()->setQualifier(resultQualifier);
1088 return;
1089 }
1090 case EOpIndexDirectInterfaceBlock:
1091 {
1092 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1093 const int i = mRight->getAsConstantUnion()->getIConst(0);
1094 setType(*fields[i]->type());
1095 getTypePointer()->setQualifier(resultQualifier);
1096 return;
1097 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001098 default:
1099 break;
1100 }
1101
1102 ASSERT(mLeft->isArray() == mRight->isArray());
1103
1104 // The result gets promoted to the highest precision.
1105 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1106 getTypePointer()->setPrecision(higherPrecision);
1107
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001108 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001109
1110 //
1111 // All scalars or structs. Code after this test assumes this case is removed!
1112 //
1113 if (nominalSize == 1)
1114 {
1115 switch (mOp)
1116 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001117 //
1118 // Promote to conditional
1119 //
1120 case EOpEqual:
1121 case EOpNotEqual:
1122 case EOpLessThan:
1123 case EOpGreaterThan:
1124 case EOpLessThanEqual:
1125 case EOpGreaterThanEqual:
1126 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1127 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001128
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001129 //
1130 // And and Or operate on conditionals
1131 //
1132 case EOpLogicalAnd:
1133 case EOpLogicalXor:
1134 case EOpLogicalOr:
1135 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1136 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1137 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001138
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001139 default:
1140 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001141 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001142 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001143 }
1144
1145 // If we reach here, at least one of the operands is vector or matrix.
1146 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001147 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001148
Jamie Madillb1a85f42014-08-19 15:23:24 -04001149 switch (mOp)
1150 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001151 case EOpMul:
1152 break;
1153 case EOpMatrixTimesScalar:
1154 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001155 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001156 setType(TType(basicType, higherPrecision, resultQualifier,
1157 static_cast<unsigned char>(mRight->getCols()),
1158 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001159 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001160 break;
1161 case EOpMatrixTimesVector:
1162 setType(TType(basicType, higherPrecision, resultQualifier,
1163 static_cast<unsigned char>(mLeft->getRows()), 1));
1164 break;
1165 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001166 setType(TType(basicType, higherPrecision, resultQualifier,
1167 static_cast<unsigned char>(mRight->getCols()),
1168 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001169 break;
1170 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001171 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001172 static_cast<unsigned char>(nominalSize), 1));
1173 break;
1174 case EOpVectorTimesMatrix:
1175 setType(TType(basicType, higherPrecision, resultQualifier,
1176 static_cast<unsigned char>(mRight->getCols()), 1));
1177 break;
1178 case EOpMulAssign:
1179 case EOpVectorTimesScalarAssign:
1180 case EOpVectorTimesMatrixAssign:
1181 case EOpMatrixTimesScalarAssign:
1182 case EOpMatrixTimesMatrixAssign:
1183 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1184 break;
1185 case EOpAssign:
1186 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001187 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1188 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1189 break;
1190 case EOpAdd:
1191 case EOpSub:
1192 case EOpDiv:
1193 case EOpIMod:
1194 case EOpBitShiftLeft:
1195 case EOpBitShiftRight:
1196 case EOpBitwiseAnd:
1197 case EOpBitwiseXor:
1198 case EOpBitwiseOr:
1199 case EOpAddAssign:
1200 case EOpSubAssign:
1201 case EOpDivAssign:
1202 case EOpIModAssign:
1203 case EOpBitShiftLeftAssign:
1204 case EOpBitShiftRightAssign:
1205 case EOpBitwiseAndAssign:
1206 case EOpBitwiseXorAssign:
1207 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001208 {
1209 const int secondarySize =
1210 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1211 setType(TType(basicType, higherPrecision, resultQualifier,
1212 static_cast<unsigned char>(nominalSize),
1213 static_cast<unsigned char>(secondarySize)));
1214 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001215 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001216 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001217 case EOpEqual:
1218 case EOpNotEqual:
1219 case EOpLessThan:
1220 case EOpGreaterThan:
1221 case EOpLessThanEqual:
1222 case EOpGreaterThanEqual:
1223 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1224 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001225 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001226 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001227
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001228 case EOpIndexDirect:
1229 case EOpIndexIndirect:
1230 case EOpIndexDirectInterfaceBlock:
1231 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001232 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001233 UNREACHABLE();
1234 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001235 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001236 UNREACHABLE();
1237 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001238 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001239}
1240
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001241const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001242{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001243 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001244 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001245 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001246 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001247 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001248 size_t arrayElementSize = arrayElementType.getObjectSize();
1249 return &mUnionArrayPointer[arrayElementSize * index];
1250 }
1251 else if (isMatrix())
1252 {
1253 ASSERT(index < getType().getCols());
1254 int size = getType().getRows();
1255 return &mUnionArrayPointer[size * index];
1256 }
1257 else if (isVector())
1258 {
1259 ASSERT(index < getType().getNominalSize());
1260 return &mUnionArrayPointer[index];
1261 }
1262 else
1263 {
1264 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001265 return nullptr;
1266 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001267}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001268
Olli Etuahob6fa0432016-09-28 16:28:05 +01001269TIntermTyped *TIntermSwizzle::fold()
1270{
1271 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1272 if (operandConstant == nullptr)
1273 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001274 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001275 }
1276
1277 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1278 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1279 {
1280 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1281 }
1282 return CreateFoldedNode(constArray, this, mType.getQualifier());
1283}
1284
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001285TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1286{
1287 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1288 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1289 switch (mOp)
1290 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001291 case EOpComma:
1292 {
1293 if (mLeft->hasSideEffects())
1294 {
1295 return this;
1296 }
1297 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1298 return mRight;
1299 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001300 case EOpIndexDirect:
1301 {
1302 if (leftConstant == nullptr || rightConstant == nullptr)
1303 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001304 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001305 }
1306 int index = rightConstant->getIConst(0);
1307
1308 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001309 if (!constArray)
1310 {
1311 return this;
1312 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001313 return CreateFoldedNode(constArray, this, mType.getQualifier());
1314 }
1315 case EOpIndexDirectStruct:
1316 {
1317 if (leftConstant == nullptr || rightConstant == nullptr)
1318 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001319 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001320 }
1321 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1322 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1323
1324 size_t previousFieldsSize = 0;
1325 for (size_t i = 0; i < index; ++i)
1326 {
1327 previousFieldsSize += fields[i]->type()->getObjectSize();
1328 }
1329
1330 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1331 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1332 }
1333 case EOpIndexIndirect:
1334 case EOpIndexDirectInterfaceBlock:
1335 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001336 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001337 default:
1338 {
1339 if (leftConstant == nullptr || rightConstant == nullptr)
1340 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001341 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001342 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001343 TConstantUnion *constArray =
1344 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001345 if (!constArray)
1346 {
1347 return this;
1348 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001349
1350 // Nodes may be constant folded without being qualified as constant.
1351 return CreateFoldedNode(constArray, this, mType.getQualifier());
1352 }
1353 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001354}
1355
Olli Etuahof119a262016-08-19 15:54:22 +03001356TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001357{
1358 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1359 if (operandConstant == nullptr)
1360 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001361 return this;
Olli Etuaho95310b02015-06-02 17:43:38 +03001362 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301363
1364 TConstantUnion *constArray = nullptr;
1365 switch (mOp)
1366 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001367 case EOpAny:
1368 case EOpAll:
1369 case EOpLength:
1370 case EOpTranspose:
1371 case EOpDeterminant:
1372 case EOpInverse:
1373 case EOpPackSnorm2x16:
1374 case EOpUnpackSnorm2x16:
1375 case EOpPackUnorm2x16:
1376 case EOpUnpackUnorm2x16:
1377 case EOpPackHalf2x16:
1378 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001379 case EOpPackUnorm4x8:
1380 case EOpPackSnorm4x8:
1381 case EOpUnpackUnorm4x8:
1382 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001383 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1384 break;
1385 default:
1386 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1387 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301388 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001389 if (constArray == nullptr)
1390 {
1391 return this;
1392 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001393
1394 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001395 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001396}
1397
Olli Etuahof119a262016-08-19 15:54:22 +03001398TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001399{
1400 // Make sure that all params are constant before actual constant folding.
1401 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001402 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001403 if (param->getAsConstantUnion() == nullptr)
1404 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001405 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001406 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001407 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001408 TConstantUnion *constArray = nullptr;
1409 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001410 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001411 else
Olli Etuahof119a262016-08-19 15:54:22 +03001412 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001413
1414 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001415 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001416}
1417
Jamie Madillb1a85f42014-08-19 15:23:24 -04001418//
1419// The fold functions see if an operation on a constant can be done in place,
1420// without generating run-time code.
1421//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001422// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001423//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001424TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1425 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001426 TDiagnostics *diagnostics,
1427 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001428{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001429 const TConstantUnion *leftArray = getUnionArrayPointer();
1430 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001431
Olli Etuahof119a262016-08-19 15:54:22 +03001432 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001433
1434 size_t objectSize = getType().getObjectSize();
1435
1436 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1437 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1438 {
1439 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1440 }
1441 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1442 {
1443 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001444 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001445 objectSize = rightNode->getType().getObjectSize();
1446 }
1447
1448 TConstantUnion *resultArray = nullptr;
1449
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001450 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001451 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001452 case EOpAdd:
1453 resultArray = new TConstantUnion[objectSize];
1454 for (size_t i = 0; i < objectSize; i++)
1455 resultArray[i] =
1456 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1457 break;
1458 case EOpSub:
1459 resultArray = new TConstantUnion[objectSize];
1460 for (size_t i = 0; i < objectSize; i++)
1461 resultArray[i] =
1462 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1463 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001464
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001465 case EOpMul:
1466 case EOpVectorTimesScalar:
1467 case EOpMatrixTimesScalar:
1468 resultArray = new TConstantUnion[objectSize];
1469 for (size_t i = 0; i < objectSize; i++)
1470 resultArray[i] =
1471 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1472 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001473
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001474 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001475 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001476 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001477 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001478
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001479 const int leftCols = getCols();
1480 const int leftRows = getRows();
1481 const int rightCols = rightNode->getType().getCols();
1482 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001483 const int resultCols = rightCols;
1484 const int resultRows = leftRows;
1485
1486 resultArray = new TConstantUnion[resultCols * resultRows];
1487 for (int row = 0; row < resultRows; row++)
1488 {
1489 for (int column = 0; column < resultCols; column++)
1490 {
1491 resultArray[resultRows * column + row].setFConst(0.0f);
1492 for (int i = 0; i < leftCols; i++)
1493 {
1494 resultArray[resultRows * column + row].setFConst(
1495 resultArray[resultRows * column + row].getFConst() +
1496 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001497 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001498 }
1499 }
1500 }
1501 }
1502 break;
1503
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001504 case EOpDiv:
1505 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001506 {
1507 resultArray = new TConstantUnion[objectSize];
1508 for (size_t i = 0; i < objectSize; i++)
1509 {
1510 switch (getType().getBasicType())
1511 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001512 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001513 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001514 ASSERT(op == EOpDiv);
1515 float dividend = leftArray[i].getFConst();
1516 float divisor = rightArray[i].getFConst();
1517 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001518 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001519 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001520 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001521 diagnostics->warning(
1522 getLine(),
1523 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001524 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001525 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001526 }
1527 else
1528 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001529 diagnostics->warning(getLine(),
1530 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001531 bool negativeResult =
1532 std::signbit(dividend) != std::signbit(divisor);
1533 resultArray[i].setFConst(
1534 negativeResult ? -std::numeric_limits<float>::infinity()
1535 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001536 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001537 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001538 else if (gl::isInf(dividend) && gl::isInf(divisor))
1539 {
1540 diagnostics->warning(getLine(),
1541 "Infinity divided by infinity during constant "
1542 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001543 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001544 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1545 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001546 else
1547 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001548 float result = dividend / divisor;
1549 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001550 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001551 diagnostics->warning(
1552 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001553 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001554 }
1555 resultArray[i].setFConst(result);
1556 }
1557 break;
1558 }
1559 case EbtInt:
1560 if (rightArray[i] == 0)
1561 {
1562 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001563 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001564 resultArray[i].setIConst(INT_MAX);
1565 }
1566 else
1567 {
1568 int lhs = leftArray[i].getIConst();
1569 int divisor = rightArray[i].getIConst();
1570 if (op == EOpDiv)
1571 {
1572 // Check for the special case where the minimum representable number
1573 // is
1574 // divided by -1. If left alone this leads to integer overflow in
1575 // C++.
1576 // ESSL 3.00.6 section 4.1.3 Integers:
1577 // "However, for the case where the minimum representable value is
1578 // divided by -1, it is allowed to return either the minimum
1579 // representable value or the maximum representable value."
1580 if (lhs == -0x7fffffff - 1 && divisor == -1)
1581 {
1582 resultArray[i].setIConst(0x7fffffff);
1583 }
1584 else
1585 {
1586 resultArray[i].setIConst(lhs / divisor);
1587 }
Olli Etuahod4453572016-09-27 13:21:46 +01001588 }
1589 else
1590 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001591 ASSERT(op == EOpIMod);
1592 if (lhs < 0 || divisor < 0)
1593 {
1594 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1595 // when
1596 // either one of the operands is negative.
1597 diagnostics->warning(getLine(),
1598 "Negative modulus operator operand "
1599 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001600 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001601 resultArray[i].setIConst(0);
1602 }
1603 else
1604 {
1605 resultArray[i].setIConst(lhs % divisor);
1606 }
Olli Etuahod4453572016-09-27 13:21:46 +01001607 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001608 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001609 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001610
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001611 case EbtUInt:
1612 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001613 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001614 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001615 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001616 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001617 }
1618 else
1619 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001620 if (op == EOpDiv)
1621 {
1622 resultArray[i].setUConst(leftArray[i].getUConst() /
1623 rightArray[i].getUConst());
1624 }
1625 else
1626 {
1627 ASSERT(op == EOpIMod);
1628 resultArray[i].setUConst(leftArray[i].getUConst() %
1629 rightArray[i].getUConst());
1630 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001631 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001632 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001633
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001634 default:
1635 UNREACHABLE();
1636 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001637 }
1638 }
1639 }
1640 break;
1641
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001642 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001643 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001644 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001645 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001646
1647 const int matrixCols = getCols();
1648 const int matrixRows = getRows();
1649
1650 resultArray = new TConstantUnion[matrixRows];
1651
1652 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1653 {
1654 resultArray[matrixRow].setFConst(0.0f);
1655 for (int col = 0; col < matrixCols; col++)
1656 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001657 resultArray[matrixRow].setFConst(
1658 resultArray[matrixRow].getFConst() +
1659 leftArray[col * matrixRows + matrixRow].getFConst() *
1660 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001661 }
1662 }
1663 }
1664 break;
1665
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001666 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001667 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001668 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001669 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001670
1671 const int matrixCols = rightNode->getType().getCols();
1672 const int matrixRows = rightNode->getType().getRows();
1673
1674 resultArray = new TConstantUnion[matrixCols];
1675
1676 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1677 {
1678 resultArray[matrixCol].setFConst(0.0f);
1679 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1680 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001681 resultArray[matrixCol].setFConst(
1682 resultArray[matrixCol].getFConst() +
1683 leftArray[matrixRow].getFConst() *
1684 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001685 }
1686 }
1687 }
1688 break;
1689
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001690 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001691 {
1692 resultArray = new TConstantUnion[objectSize];
1693 for (size_t i = 0; i < objectSize; i++)
1694 {
1695 resultArray[i] = leftArray[i] && rightArray[i];
1696 }
1697 }
1698 break;
1699
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001700 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001701 {
1702 resultArray = new TConstantUnion[objectSize];
1703 for (size_t i = 0; i < objectSize; i++)
1704 {
1705 resultArray[i] = leftArray[i] || rightArray[i];
1706 }
1707 }
1708 break;
1709
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001710 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001711 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001712 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001713 resultArray = new TConstantUnion[objectSize];
1714 for (size_t i = 0; i < objectSize; i++)
1715 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001716 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001717 }
1718 }
1719 break;
1720
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001721 case EOpBitwiseAnd:
1722 resultArray = new TConstantUnion[objectSize];
1723 for (size_t i = 0; i < objectSize; i++)
1724 resultArray[i] = leftArray[i] & rightArray[i];
1725 break;
1726 case EOpBitwiseXor:
1727 resultArray = new TConstantUnion[objectSize];
1728 for (size_t i = 0; i < objectSize; i++)
1729 resultArray[i] = leftArray[i] ^ rightArray[i];
1730 break;
1731 case EOpBitwiseOr:
1732 resultArray = new TConstantUnion[objectSize];
1733 for (size_t i = 0; i < objectSize; i++)
1734 resultArray[i] = leftArray[i] | rightArray[i];
1735 break;
1736 case EOpBitShiftLeft:
1737 resultArray = new TConstantUnion[objectSize];
1738 for (size_t i = 0; i < objectSize; i++)
1739 resultArray[i] =
1740 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1741 break;
1742 case EOpBitShiftRight:
1743 resultArray = new TConstantUnion[objectSize];
1744 for (size_t i = 0; i < objectSize; i++)
1745 resultArray[i] =
1746 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1747 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001748
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001749 case EOpLessThan:
1750 ASSERT(objectSize == 1);
1751 resultArray = new TConstantUnion[1];
1752 resultArray->setBConst(*leftArray < *rightArray);
1753 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001754
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001755 case EOpGreaterThan:
1756 ASSERT(objectSize == 1);
1757 resultArray = new TConstantUnion[1];
1758 resultArray->setBConst(*leftArray > *rightArray);
1759 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001760
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001761 case EOpLessThanEqual:
1762 ASSERT(objectSize == 1);
1763 resultArray = new TConstantUnion[1];
1764 resultArray->setBConst(!(*leftArray > *rightArray));
1765 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001766
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001767 case EOpGreaterThanEqual:
1768 ASSERT(objectSize == 1);
1769 resultArray = new TConstantUnion[1];
1770 resultArray->setBConst(!(*leftArray < *rightArray));
1771 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001772
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001773 case EOpEqual:
1774 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001775 {
1776 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001777 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001778 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001779 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001780 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001781 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001782 equal = false;
1783 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001784 }
1785 }
1786 if (op == EOpEqual)
1787 {
1788 resultArray->setBConst(equal);
1789 }
1790 else
1791 {
1792 resultArray->setBConst(!equal);
1793 }
1794 }
1795 break;
1796
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001797 default:
1798 UNREACHABLE();
1799 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001800 }
1801 return resultArray;
1802}
1803
Olli Etuahof119a262016-08-19 15:54:22 +03001804// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1805// code. Returns the constant value to keep using. Nullptr should not be returned.
1806TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001807{
Olli Etuahof119a262016-08-19 15:54:22 +03001808 // Do operations where the return type may have a different number of components compared to the
1809 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001810
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001811 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001812 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301813
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001814 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301815 TConstantUnion *resultArray = nullptr;
1816 switch (op)
1817 {
Olli Etuahof119a262016-08-19 15:54:22 +03001818 case EOpAny:
1819 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301820 resultArray = new TConstantUnion();
1821 resultArray->setBConst(false);
1822 for (size_t i = 0; i < objectSize; i++)
1823 {
1824 if (operandArray[i].getBConst())
1825 {
1826 resultArray->setBConst(true);
1827 break;
1828 }
1829 }
1830 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301831
Olli Etuahof119a262016-08-19 15:54:22 +03001832 case EOpAll:
1833 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301834 resultArray = new TConstantUnion();
1835 resultArray->setBConst(true);
1836 for (size_t i = 0; i < objectSize; i++)
1837 {
1838 if (!operandArray[i].getBConst())
1839 {
1840 resultArray->setBConst(false);
1841 break;
1842 }
1843 }
1844 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301845
Olli Etuahof119a262016-08-19 15:54:22 +03001846 case EOpLength:
1847 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301848 resultArray = new TConstantUnion();
1849 resultArray->setFConst(VectorLength(operandArray, objectSize));
1850 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301851
Olli Etuahof119a262016-08-19 15:54:22 +03001852 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301853 {
Olli Etuahof119a262016-08-19 15:54:22 +03001854 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301855 resultArray = new TConstantUnion[objectSize];
1856 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001857 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301858 SetUnionArrayFromMatrix(result, resultArray);
1859 break;
1860 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301861
Olli Etuahof119a262016-08-19 15:54:22 +03001862 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301863 {
Olli Etuahof119a262016-08-19 15:54:22 +03001864 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301865 unsigned int size = getType().getNominalSize();
1866 ASSERT(size >= 2 && size <= 4);
1867 resultArray = new TConstantUnion();
1868 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1869 break;
1870 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301871
Olli Etuahof119a262016-08-19 15:54:22 +03001872 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301873 {
Olli Etuahof119a262016-08-19 15:54:22 +03001874 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301875 unsigned int size = getType().getNominalSize();
1876 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001877 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301878 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1879 SetUnionArrayFromMatrix(result, resultArray);
1880 break;
1881 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301882
Olli Etuahof119a262016-08-19 15:54:22 +03001883 case EOpPackSnorm2x16:
1884 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301885 ASSERT(getType().getNominalSize() == 2);
1886 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001887 resultArray->setUConst(
1888 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301889 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301890
Olli Etuahof119a262016-08-19 15:54:22 +03001891 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301892 {
Olli Etuahof119a262016-08-19 15:54:22 +03001893 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301894 resultArray = new TConstantUnion[2];
1895 float f1, f2;
1896 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1897 resultArray[0].setFConst(f1);
1898 resultArray[1].setFConst(f2);
1899 break;
1900 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301901
Olli Etuahof119a262016-08-19 15:54:22 +03001902 case EOpPackUnorm2x16:
1903 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301904 ASSERT(getType().getNominalSize() == 2);
1905 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001906 resultArray->setUConst(
1907 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301908 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301909
Olli Etuahof119a262016-08-19 15:54:22 +03001910 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301911 {
Olli Etuahof119a262016-08-19 15:54:22 +03001912 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301913 resultArray = new TConstantUnion[2];
1914 float f1, f2;
1915 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1916 resultArray[0].setFConst(f1);
1917 resultArray[1].setFConst(f2);
1918 break;
1919 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301920
Olli Etuahof119a262016-08-19 15:54:22 +03001921 case EOpPackHalf2x16:
1922 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301923 ASSERT(getType().getNominalSize() == 2);
1924 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001925 resultArray->setUConst(
1926 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301927 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301928
Olli Etuahof119a262016-08-19 15:54:22 +03001929 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301930 {
Olli Etuahof119a262016-08-19 15:54:22 +03001931 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301932 resultArray = new TConstantUnion[2];
1933 float f1, f2;
1934 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1935 resultArray[0].setFConst(f1);
1936 resultArray[1].setFConst(f2);
1937 break;
1938 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301939
Olli Etuaho25aef452017-01-29 16:15:44 -08001940 case EOpPackUnorm4x8:
1941 {
1942 ASSERT(getType().getBasicType() == EbtFloat);
1943 resultArray = new TConstantUnion();
1944 resultArray->setUConst(
1945 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1946 operandArray[2].getFConst(), operandArray[3].getFConst()));
1947 break;
1948 }
1949 case EOpPackSnorm4x8:
1950 {
1951 ASSERT(getType().getBasicType() == EbtFloat);
1952 resultArray = new TConstantUnion();
1953 resultArray->setUConst(
1954 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1955 operandArray[2].getFConst(), operandArray[3].getFConst()));
1956 break;
1957 }
1958 case EOpUnpackUnorm4x8:
1959 {
1960 ASSERT(getType().getBasicType() == EbtUInt);
1961 resultArray = new TConstantUnion[4];
1962 float f[4];
1963 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
1964 for (size_t i = 0; i < 4; ++i)
1965 {
1966 resultArray[i].setFConst(f[i]);
1967 }
1968 break;
1969 }
1970 case EOpUnpackSnorm4x8:
1971 {
1972 ASSERT(getType().getBasicType() == EbtUInt);
1973 resultArray = new TConstantUnion[4];
1974 float f[4];
1975 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
1976 for (size_t i = 0; i < 4; ++i)
1977 {
1978 resultArray[i].setFConst(f[i]);
1979 }
1980 break;
1981 }
1982
Olli Etuahof119a262016-08-19 15:54:22 +03001983 default:
1984 UNREACHABLE();
1985 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301986 }
1987
1988 return resultArray;
1989}
1990
Olli Etuahof119a262016-08-19 15:54:22 +03001991TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1992 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301993{
Olli Etuahof119a262016-08-19 15:54:22 +03001994 // Do unary operations where each component of the result is computed based on the corresponding
1995 // component of the operand. Also folds normalize, though the divisor in that case takes all
1996 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301997
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001998 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001999 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002000
2001 size_t objectSize = getType().getObjectSize();
2002
Arun Patoleab2b9a22015-07-06 18:27:56 +05302003 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2004 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302005 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002006 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302007 {
Olli Etuahof119a262016-08-19 15:54:22 +03002008 case EOpNegative:
2009 switch (getType().getBasicType())
2010 {
2011 case EbtFloat:
2012 resultArray[i].setFConst(-operandArray[i].getFConst());
2013 break;
2014 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002015 if (operandArray[i] == std::numeric_limits<int>::min())
2016 {
2017 // The minimum representable integer doesn't have a positive
2018 // counterpart, rather the negation overflows and in ESSL is supposed to
2019 // wrap back to the minimum representable integer. Make sure that we
2020 // don't actually let the negation overflow, which has undefined
2021 // behavior in C++.
2022 resultArray[i].setIConst(std::numeric_limits<int>::min());
2023 }
2024 else
2025 {
2026 resultArray[i].setIConst(-operandArray[i].getIConst());
2027 }
Olli Etuahof119a262016-08-19 15:54:22 +03002028 break;
2029 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002030 if (operandArray[i] == 0x80000000u)
2031 {
2032 resultArray[i].setUConst(0x80000000u);
2033 }
2034 else
2035 {
2036 resultArray[i].setUConst(static_cast<unsigned int>(
2037 -static_cast<int>(operandArray[i].getUConst())));
2038 }
Olli Etuahof119a262016-08-19 15:54:22 +03002039 break;
2040 default:
2041 UNREACHABLE();
2042 return nullptr;
2043 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302044 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302045
Olli Etuahof119a262016-08-19 15:54:22 +03002046 case EOpPositive:
2047 switch (getType().getBasicType())
2048 {
2049 case EbtFloat:
2050 resultArray[i].setFConst(operandArray[i].getFConst());
2051 break;
2052 case EbtInt:
2053 resultArray[i].setIConst(operandArray[i].getIConst());
2054 break;
2055 case EbtUInt:
2056 resultArray[i].setUConst(static_cast<unsigned int>(
2057 static_cast<int>(operandArray[i].getUConst())));
2058 break;
2059 default:
2060 UNREACHABLE();
2061 return nullptr;
2062 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302063 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302064
Olli Etuahof119a262016-08-19 15:54:22 +03002065 case EOpLogicalNot:
2066 switch (getType().getBasicType())
2067 {
2068 case EbtBool:
2069 resultArray[i].setBConst(!operandArray[i].getBConst());
2070 break;
2071 default:
2072 UNREACHABLE();
2073 return nullptr;
2074 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302075 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302076
Olli Etuahof119a262016-08-19 15:54:22 +03002077 case EOpBitwiseNot:
2078 switch (getType().getBasicType())
2079 {
2080 case EbtInt:
2081 resultArray[i].setIConst(~operandArray[i].getIConst());
2082 break;
2083 case EbtUInt:
2084 resultArray[i].setUConst(~operandArray[i].getUConst());
2085 break;
2086 default:
2087 UNREACHABLE();
2088 return nullptr;
2089 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302090 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302091
Olli Etuahof119a262016-08-19 15:54:22 +03002092 case EOpRadians:
2093 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302094 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2095 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302096
Olli Etuahof119a262016-08-19 15:54:22 +03002097 case EOpDegrees:
2098 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302099 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2100 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302101
Olli Etuahof119a262016-08-19 15:54:22 +03002102 case EOpSin:
2103 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302104 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302105
Olli Etuahof119a262016-08-19 15:54:22 +03002106 case EOpCos:
2107 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2108 break;
2109
2110 case EOpTan:
2111 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2112 break;
2113
2114 case EOpAsin:
2115 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2116 // 0.
2117 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2118 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2119 diagnostics, &resultArray[i]);
2120 else
2121 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2122 break;
2123
2124 case EOpAcos:
2125 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2126 // 0.
2127 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2128 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2129 diagnostics, &resultArray[i]);
2130 else
2131 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2132 break;
2133
2134 case EOpAtan:
2135 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2136 break;
2137
2138 case EOpSinh:
2139 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2140 break;
2141
2142 case EOpCosh:
2143 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2144 break;
2145
2146 case EOpTanh:
2147 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2148 break;
2149
2150 case EOpAsinh:
2151 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2152 break;
2153
2154 case EOpAcosh:
2155 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2156 if (operandArray[i].getFConst() < 1.0f)
2157 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2158 diagnostics, &resultArray[i]);
2159 else
2160 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2161 break;
2162
2163 case EOpAtanh:
2164 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2165 // 0.
2166 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2167 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2168 diagnostics, &resultArray[i]);
2169 else
2170 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2171 break;
2172
2173 case EOpAbs:
2174 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302175 {
Olli Etuahof119a262016-08-19 15:54:22 +03002176 case EbtFloat:
2177 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2178 break;
2179 case EbtInt:
2180 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2181 break;
2182 default:
2183 UNREACHABLE();
2184 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302185 }
2186 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002187
2188 case EOpSign:
2189 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302190 {
Olli Etuahof119a262016-08-19 15:54:22 +03002191 case EbtFloat:
2192 {
2193 float fConst = operandArray[i].getFConst();
2194 float fResult = 0.0f;
2195 if (fConst > 0.0f)
2196 fResult = 1.0f;
2197 else if (fConst < 0.0f)
2198 fResult = -1.0f;
2199 resultArray[i].setFConst(fResult);
2200 break;
2201 }
2202 case EbtInt:
2203 {
2204 int iConst = operandArray[i].getIConst();
2205 int iResult = 0;
2206 if (iConst > 0)
2207 iResult = 1;
2208 else if (iConst < 0)
2209 iResult = -1;
2210 resultArray[i].setIConst(iResult);
2211 break;
2212 }
2213 default:
2214 UNREACHABLE();
2215 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302216 }
2217 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302218
Olli Etuahof119a262016-08-19 15:54:22 +03002219 case EOpFloor:
2220 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2221 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302222
Olli Etuahof119a262016-08-19 15:54:22 +03002223 case EOpTrunc:
2224 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2225 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302226
Olli Etuahof119a262016-08-19 15:54:22 +03002227 case EOpRound:
2228 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2229 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302230
Olli Etuahof119a262016-08-19 15:54:22 +03002231 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302232 {
Olli Etuahof119a262016-08-19 15:54:22 +03002233 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302234 float x = operandArray[i].getFConst();
2235 float result;
2236 float fractPart = modff(x, &result);
2237 if (fabsf(fractPart) == 0.5f)
2238 result = 2.0f * roundf(x / 2.0f);
2239 else
2240 result = roundf(x);
2241 resultArray[i].setFConst(result);
2242 break;
2243 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302244
Olli Etuahof119a262016-08-19 15:54:22 +03002245 case EOpCeil:
2246 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2247 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302248
Olli Etuahof119a262016-08-19 15:54:22 +03002249 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302250 {
Olli Etuahof119a262016-08-19 15:54:22 +03002251 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302252 float x = operandArray[i].getFConst();
2253 resultArray[i].setFConst(x - floorf(x));
2254 break;
2255 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302256
Olli Etuahof119a262016-08-19 15:54:22 +03002257 case EOpIsNan:
2258 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302259 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2260 break;
Arun Patole551279e2015-07-07 18:18:23 +05302261
Olli Etuahof119a262016-08-19 15:54:22 +03002262 case EOpIsInf:
2263 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302264 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2265 break;
Arun Patole551279e2015-07-07 18:18:23 +05302266
Olli Etuahof119a262016-08-19 15:54:22 +03002267 case EOpFloatBitsToInt:
2268 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302269 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2270 break;
Arun Patole551279e2015-07-07 18:18:23 +05302271
Olli Etuahof119a262016-08-19 15:54:22 +03002272 case EOpFloatBitsToUint:
2273 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302274 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2275 break;
Arun Patole551279e2015-07-07 18:18:23 +05302276
Olli Etuahof119a262016-08-19 15:54:22 +03002277 case EOpIntBitsToFloat:
2278 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302279 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2280 break;
Arun Patole551279e2015-07-07 18:18:23 +05302281
Olli Etuahof119a262016-08-19 15:54:22 +03002282 case EOpUintBitsToFloat:
2283 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302284 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2285 break;
Arun Patole551279e2015-07-07 18:18:23 +05302286
Olli Etuahof119a262016-08-19 15:54:22 +03002287 case EOpExp:
2288 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2289 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302290
Olli Etuahof119a262016-08-19 15:54:22 +03002291 case EOpLog:
2292 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2293 if (operandArray[i].getFConst() <= 0.0f)
2294 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2295 diagnostics, &resultArray[i]);
2296 else
2297 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2298 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302299
Olli Etuahof119a262016-08-19 15:54:22 +03002300 case EOpExp2:
2301 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2302 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302303
Olli Etuahof119a262016-08-19 15:54:22 +03002304 case EOpLog2:
2305 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2306 // And log2f is not available on some plarforms like old android, so just using
2307 // log(x)/log(2) here.
2308 if (operandArray[i].getFConst() <= 0.0f)
2309 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2310 diagnostics, &resultArray[i]);
2311 else
2312 {
2313 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2314 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2315 }
2316 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302317
Olli Etuahof119a262016-08-19 15:54:22 +03002318 case EOpSqrt:
2319 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2320 if (operandArray[i].getFConst() < 0.0f)
2321 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2322 diagnostics, &resultArray[i]);
2323 else
2324 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2325 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302326
Olli Etuahof119a262016-08-19 15:54:22 +03002327 case EOpInverseSqrt:
2328 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2329 // so getting the square root first using builtin function sqrt() and then taking
2330 // its inverse.
2331 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2332 // result to 0.
2333 if (operandArray[i].getFConst() <= 0.0f)
2334 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2335 diagnostics, &resultArray[i]);
2336 else
2337 {
2338 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2339 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2340 }
2341 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302342
Olli Etuahod68924e2017-01-02 17:34:40 +00002343 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002344 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302345 resultArray[i].setBConst(!operandArray[i].getBConst());
2346 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302347
Olli Etuahof119a262016-08-19 15:54:22 +03002348 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302349 {
Olli Etuahof119a262016-08-19 15:54:22 +03002350 ASSERT(getType().getBasicType() == EbtFloat);
2351 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302352 float length = VectorLength(operandArray, objectSize);
2353 if (length)
2354 resultArray[i].setFConst(x / length);
2355 else
Olli Etuahof119a262016-08-19 15:54:22 +03002356 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2357 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302358 break;
2359 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002360 case EOpBitfieldReverse:
2361 {
2362 uint32_t value;
2363 if (getType().getBasicType() == EbtInt)
2364 {
2365 value = static_cast<uint32_t>(operandArray[i].getIConst());
2366 }
2367 else
2368 {
2369 ASSERT(getType().getBasicType() == EbtUInt);
2370 value = operandArray[i].getUConst();
2371 }
2372 uint32_t result = gl::BitfieldReverse(value);
2373 if (getType().getBasicType() == EbtInt)
2374 {
2375 resultArray[i].setIConst(static_cast<int32_t>(result));
2376 }
2377 else
2378 {
2379 resultArray[i].setUConst(result);
2380 }
2381 break;
2382 }
2383 case EOpBitCount:
2384 {
2385 uint32_t value;
2386 if (getType().getBasicType() == EbtInt)
2387 {
2388 value = static_cast<uint32_t>(operandArray[i].getIConst());
2389 }
2390 else
2391 {
2392 ASSERT(getType().getBasicType() == EbtUInt);
2393 value = operandArray[i].getUConst();
2394 }
2395 int result = gl::BitCount(value);
2396 resultArray[i].setIConst(result);
2397 break;
2398 }
2399 case EOpFindLSB:
2400 {
2401 uint32_t value;
2402 if (getType().getBasicType() == EbtInt)
2403 {
2404 value = static_cast<uint32_t>(operandArray[i].getIConst());
2405 }
2406 else
2407 {
2408 ASSERT(getType().getBasicType() == EbtUInt);
2409 value = operandArray[i].getUConst();
2410 }
2411 resultArray[i].setIConst(gl::FindLSB(value));
2412 break;
2413 }
2414 case EOpFindMSB:
2415 {
2416 uint32_t value;
2417 if (getType().getBasicType() == EbtInt)
2418 {
2419 int intValue = operandArray[i].getIConst();
2420 value = static_cast<uint32_t>(intValue);
2421 if (intValue < 0)
2422 {
2423 // Look for zero instead of one in value. This also handles the intValue ==
2424 // -1 special case, where the return value needs to be -1.
2425 value = ~value;
2426 }
2427 }
2428 else
2429 {
2430 ASSERT(getType().getBasicType() == EbtUInt);
2431 value = operandArray[i].getUConst();
2432 }
2433 resultArray[i].setIConst(gl::FindMSB(value));
2434 break;
2435 }
Olli Etuahof119a262016-08-19 15:54:22 +03002436 case EOpDFdx:
2437 case EOpDFdy:
2438 case EOpFwidth:
2439 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302440 // Derivatives of constant arguments should be 0.
2441 resultArray[i].setFConst(0.0f);
2442 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302443
Olli Etuahof119a262016-08-19 15:54:22 +03002444 default:
2445 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302446 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302447 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002448
Arun Patoleab2b9a22015-07-06 18:27:56 +05302449 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002450}
2451
Olli Etuahof119a262016-08-19 15:54:22 +03002452void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2453 FloatTypeUnaryFunc builtinFunc,
2454 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302455{
2456 ASSERT(builtinFunc);
2457
Olli Etuahof119a262016-08-19 15:54:22 +03002458 ASSERT(getType().getBasicType() == EbtFloat);
2459 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302460}
2461
Jamie Madillb1a85f42014-08-19 15:23:24 -04002462// static
Olli Etuahof119a262016-08-19 15:54:22 +03002463TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002464{
2465 ASSERT(aggregate->getSequence()->size() > 0u);
2466 size_t resultSize = aggregate->getType().getObjectSize();
2467 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2468 TBasicType basicType = aggregate->getBasicType();
2469
2470 size_t resultIndex = 0u;
2471
2472 if (aggregate->getSequence()->size() == 1u)
2473 {
2474 TIntermNode *argument = aggregate->getSequence()->front();
2475 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2476 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2477 // Check the special case of constructing a matrix diagonal from a single scalar,
2478 // or a vector from a single scalar.
2479 if (argumentConstant->getType().getObjectSize() == 1u)
2480 {
2481 if (aggregate->isMatrix())
2482 {
2483 int resultCols = aggregate->getType().getCols();
2484 int resultRows = aggregate->getType().getRows();
2485 for (int col = 0; col < resultCols; ++col)
2486 {
2487 for (int row = 0; row < resultRows; ++row)
2488 {
2489 if (col == row)
2490 {
2491 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2492 }
2493 else
2494 {
2495 resultArray[resultIndex].setFConst(0.0f);
2496 }
2497 ++resultIndex;
2498 }
2499 }
2500 }
2501 else
2502 {
2503 while (resultIndex < resultSize)
2504 {
2505 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2506 ++resultIndex;
2507 }
2508 }
2509 ASSERT(resultIndex == resultSize);
2510 return resultArray;
2511 }
2512 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2513 {
2514 // The special case of constructing a matrix from a matrix.
2515 int argumentCols = argumentConstant->getType().getCols();
2516 int argumentRows = argumentConstant->getType().getRows();
2517 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002518 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002519 for (int col = 0; col < resultCols; ++col)
2520 {
2521 for (int row = 0; row < resultRows; ++row)
2522 {
2523 if (col < argumentCols && row < argumentRows)
2524 {
2525 resultArray[resultIndex].cast(basicType,
2526 argumentUnionArray[col * argumentRows + row]);
2527 }
2528 else if (col == row)
2529 {
2530 resultArray[resultIndex].setFConst(1.0f);
2531 }
2532 else
2533 {
2534 resultArray[resultIndex].setFConst(0.0f);
2535 }
2536 ++resultIndex;
2537 }
2538 }
2539 ASSERT(resultIndex == resultSize);
2540 return resultArray;
2541 }
2542 }
2543
2544 for (TIntermNode *&argument : *aggregate->getSequence())
2545 {
2546 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2547 size_t argumentSize = argumentConstant->getType().getObjectSize();
2548 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2549 for (size_t i = 0u; i < argumentSize; ++i)
2550 {
2551 if (resultIndex >= resultSize)
2552 break;
2553 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2554 ++resultIndex;
2555 }
2556 }
2557 ASSERT(resultIndex == resultSize);
2558 return resultArray;
2559}
2560
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002561bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2562{
2563 switch (op)
2564 {
2565 case EOpAtan:
2566 case EOpPow:
2567 case EOpMod:
2568 case EOpMin:
2569 case EOpMax:
2570 case EOpClamp:
2571 case EOpMix:
2572 case EOpStep:
2573 case EOpSmoothStep:
2574 case EOpLdexp:
2575 case EOpMulMatrixComponentWise:
2576 case EOpOuterProduct:
2577 case EOpEqualComponentWise:
2578 case EOpNotEqualComponentWise:
2579 case EOpLessThanComponentWise:
2580 case EOpLessThanEqualComponentWise:
2581 case EOpGreaterThanComponentWise:
2582 case EOpGreaterThanEqualComponentWise:
2583 case EOpDistance:
2584 case EOpDot:
2585 case EOpCross:
2586 case EOpFaceforward:
2587 case EOpReflect:
2588 case EOpRefract:
2589 case EOpBitfieldExtract:
2590 case EOpBitfieldInsert:
2591 return true;
2592 default:
2593 return false;
2594 }
2595}
2596
Olli Etuaho1d122782015-11-06 15:35:17 +02002597// static
Olli Etuahof119a262016-08-19 15:54:22 +03002598TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2599 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302600{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002601 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002602 TIntermSequence *arguments = aggregate->getSequence();
2603 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2604 std::vector<const TConstantUnion *> unionArrays(argsCount);
2605 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002606 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302607 TBasicType basicType = EbtVoid;
2608 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002609 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302610 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002611 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2612 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302613
2614 if (i == 0)
2615 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002616 basicType = argConstant->getType().getBasicType();
2617 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302618 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002619 unionArrays[i] = argConstant->getUnionArrayPointer();
2620 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002621 if (objectSizes[i] > maxObjectSize)
2622 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302623 }
2624
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002625 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302626 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002627 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302628 if (objectSizes[i] != maxObjectSize)
2629 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2630 }
Arun Patole274f0702015-05-05 13:33:30 +05302631
Olli Etuahob43846e2015-06-02 18:18:57 +03002632 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002633
2634 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302635 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002636 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302637 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002638 ASSERT(basicType == EbtFloat);
2639 resultArray = new TConstantUnion[maxObjectSize];
2640 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302641 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002642 float y = unionArrays[0][i].getFConst();
2643 float x = unionArrays[1][i].getFConst();
2644 // Results are undefined if x and y are both 0.
2645 if (x == 0.0f && y == 0.0f)
2646 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2647 else
2648 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302649 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002650 break;
2651 }
Arun Patolebf790422015-05-18 17:53:04 +05302652
Olli Etuaho51182ab2017-01-22 00:12:29 +00002653 case EOpPow:
2654 {
2655 ASSERT(basicType == EbtFloat);
2656 resultArray = new TConstantUnion[maxObjectSize];
2657 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302658 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002659 float x = unionArrays[0][i].getFConst();
2660 float y = unionArrays[1][i].getFConst();
2661 // Results are undefined if x < 0.
2662 // Results are undefined if x = 0 and y <= 0.
2663 if (x < 0.0f)
2664 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2665 else if (x == 0.0f && y <= 0.0f)
2666 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2667 else
2668 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302669 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002670 break;
2671 }
Arun Patolebf790422015-05-18 17:53:04 +05302672
Olli Etuaho51182ab2017-01-22 00:12:29 +00002673 case EOpMod:
2674 {
2675 ASSERT(basicType == EbtFloat);
2676 resultArray = new TConstantUnion[maxObjectSize];
2677 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302678 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002679 float x = unionArrays[0][i].getFConst();
2680 float y = unionArrays[1][i].getFConst();
2681 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302682 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002683 break;
2684 }
Arun Patolebf790422015-05-18 17:53:04 +05302685
Olli Etuaho51182ab2017-01-22 00:12:29 +00002686 case EOpMin:
2687 {
2688 resultArray = new TConstantUnion[maxObjectSize];
2689 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302690 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002691 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302692 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002693 case EbtFloat:
2694 resultArray[i].setFConst(
2695 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2696 break;
2697 case EbtInt:
2698 resultArray[i].setIConst(
2699 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2700 break;
2701 case EbtUInt:
2702 resultArray[i].setUConst(
2703 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2704 break;
2705 default:
2706 UNREACHABLE();
2707 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302708 }
2709 }
2710 break;
Arun Patole274f0702015-05-05 13:33:30 +05302711 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002712
2713 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302714 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002715 resultArray = new TConstantUnion[maxObjectSize];
2716 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302717 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002718 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302719 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002720 case EbtFloat:
2721 resultArray[i].setFConst(
2722 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2723 break;
2724 case EbtInt:
2725 resultArray[i].setIConst(
2726 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2727 break;
2728 case EbtUInt:
2729 resultArray[i].setUConst(
2730 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2731 break;
2732 default:
2733 UNREACHABLE();
2734 break;
Arun Patole274f0702015-05-05 13:33:30 +05302735 }
2736 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002737 break;
Arun Patole274f0702015-05-05 13:33:30 +05302738 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002739
2740 case EOpStep:
2741 {
2742 ASSERT(basicType == EbtFloat);
2743 resultArray = new TConstantUnion[maxObjectSize];
2744 for (size_t i = 0; i < maxObjectSize; i++)
2745 resultArray[i].setFConst(
2746 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2747 break;
2748 }
2749
2750 case EOpLessThanComponentWise:
2751 {
2752 resultArray = new TConstantUnion[maxObjectSize];
2753 for (size_t i = 0; i < maxObjectSize; i++)
2754 {
2755 switch (basicType)
2756 {
2757 case EbtFloat:
2758 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2759 unionArrays[1][i].getFConst());
2760 break;
2761 case EbtInt:
2762 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2763 unionArrays[1][i].getIConst());
2764 break;
2765 case EbtUInt:
2766 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2767 unionArrays[1][i].getUConst());
2768 break;
2769 default:
2770 UNREACHABLE();
2771 break;
2772 }
2773 }
2774 break;
2775 }
2776
2777 case EOpLessThanEqualComponentWise:
2778 {
2779 resultArray = new TConstantUnion[maxObjectSize];
2780 for (size_t i = 0; i < maxObjectSize; i++)
2781 {
2782 switch (basicType)
2783 {
2784 case EbtFloat:
2785 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2786 unionArrays[1][i].getFConst());
2787 break;
2788 case EbtInt:
2789 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2790 unionArrays[1][i].getIConst());
2791 break;
2792 case EbtUInt:
2793 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2794 unionArrays[1][i].getUConst());
2795 break;
2796 default:
2797 UNREACHABLE();
2798 break;
2799 }
2800 }
2801 break;
2802 }
2803
2804 case EOpGreaterThanComponentWise:
2805 {
2806 resultArray = new TConstantUnion[maxObjectSize];
2807 for (size_t i = 0; i < maxObjectSize; i++)
2808 {
2809 switch (basicType)
2810 {
2811 case EbtFloat:
2812 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2813 unionArrays[1][i].getFConst());
2814 break;
2815 case EbtInt:
2816 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2817 unionArrays[1][i].getIConst());
2818 break;
2819 case EbtUInt:
2820 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2821 unionArrays[1][i].getUConst());
2822 break;
2823 default:
2824 UNREACHABLE();
2825 break;
2826 }
2827 }
2828 break;
2829 }
2830 case EOpGreaterThanEqualComponentWise:
2831 {
2832 resultArray = new TConstantUnion[maxObjectSize];
2833 for (size_t i = 0; i < maxObjectSize; i++)
2834 {
2835 switch (basicType)
2836 {
2837 case EbtFloat:
2838 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2839 unionArrays[1][i].getFConst());
2840 break;
2841 case EbtInt:
2842 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2843 unionArrays[1][i].getIConst());
2844 break;
2845 case EbtUInt:
2846 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2847 unionArrays[1][i].getUConst());
2848 break;
2849 default:
2850 UNREACHABLE();
2851 break;
2852 }
2853 }
2854 }
2855 break;
2856
2857 case EOpEqualComponentWise:
2858 {
2859 resultArray = new TConstantUnion[maxObjectSize];
2860 for (size_t i = 0; i < maxObjectSize; i++)
2861 {
2862 switch (basicType)
2863 {
2864 case EbtFloat:
2865 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2866 unionArrays[1][i].getFConst());
2867 break;
2868 case EbtInt:
2869 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2870 unionArrays[1][i].getIConst());
2871 break;
2872 case EbtUInt:
2873 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2874 unionArrays[1][i].getUConst());
2875 break;
2876 case EbtBool:
2877 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2878 unionArrays[1][i].getBConst());
2879 break;
2880 default:
2881 UNREACHABLE();
2882 break;
2883 }
2884 }
2885 break;
2886 }
2887
2888 case EOpNotEqualComponentWise:
2889 {
2890 resultArray = new TConstantUnion[maxObjectSize];
2891 for (size_t i = 0; i < maxObjectSize; i++)
2892 {
2893 switch (basicType)
2894 {
2895 case EbtFloat:
2896 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2897 unionArrays[1][i].getFConst());
2898 break;
2899 case EbtInt:
2900 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2901 unionArrays[1][i].getIConst());
2902 break;
2903 case EbtUInt:
2904 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2905 unionArrays[1][i].getUConst());
2906 break;
2907 case EbtBool:
2908 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2909 unionArrays[1][i].getBConst());
2910 break;
2911 default:
2912 UNREACHABLE();
2913 break;
2914 }
2915 }
2916 break;
2917 }
2918
2919 case EOpDistance:
2920 {
2921 ASSERT(basicType == EbtFloat);
2922 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2923 resultArray = new TConstantUnion();
2924 for (size_t i = 0; i < maxObjectSize; i++)
2925 {
2926 float x = unionArrays[0][i].getFConst();
2927 float y = unionArrays[1][i].getFConst();
2928 distanceArray[i].setFConst(x - y);
2929 }
2930 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2931 break;
2932 }
2933
2934 case EOpDot:
2935 ASSERT(basicType == EbtFloat);
2936 resultArray = new TConstantUnion();
2937 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2938 break;
2939
2940 case EOpCross:
2941 {
2942 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2943 resultArray = new TConstantUnion[maxObjectSize];
2944 float x0 = unionArrays[0][0].getFConst();
2945 float x1 = unionArrays[0][1].getFConst();
2946 float x2 = unionArrays[0][2].getFConst();
2947 float y0 = unionArrays[1][0].getFConst();
2948 float y1 = unionArrays[1][1].getFConst();
2949 float y2 = unionArrays[1][2].getFConst();
2950 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2951 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2952 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2953 break;
2954 }
2955
2956 case EOpReflect:
2957 {
2958 ASSERT(basicType == EbtFloat);
2959 // genType reflect (genType I, genType N) :
2960 // For the incident vector I and surface orientation N, returns the reflection
2961 // direction:
2962 // I - 2 * dot(N, I) * N.
2963 resultArray = new TConstantUnion[maxObjectSize];
2964 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2965 for (size_t i = 0; i < maxObjectSize; i++)
2966 {
2967 float result = unionArrays[0][i].getFConst() -
2968 2.0f * dotProduct * unionArrays[1][i].getFConst();
2969 resultArray[i].setFConst(result);
2970 }
2971 break;
2972 }
2973
2974 case EOpMulMatrixComponentWise:
2975 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002976 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
2977 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00002978 // Perform component-wise matrix multiplication.
2979 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002980 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002981 angle::Matrix<float> result =
2982 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2983 SetUnionArrayFromMatrix(result, resultArray);
2984 break;
2985 }
2986
2987 case EOpOuterProduct:
2988 {
2989 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002990 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
2991 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00002992 resultArray = new TConstantUnion[numRows * numCols];
2993 angle::Matrix<float> result =
2994 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2995 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
2996 SetUnionArrayFromMatrix(result, resultArray);
2997 break;
2998 }
2999
3000 case EOpClamp:
3001 {
3002 resultArray = new TConstantUnion[maxObjectSize];
3003 for (size_t i = 0; i < maxObjectSize; i++)
3004 {
3005 switch (basicType)
3006 {
3007 case EbtFloat:
3008 {
3009 float x = unionArrays[0][i].getFConst();
3010 float min = unionArrays[1][i].getFConst();
3011 float max = unionArrays[2][i].getFConst();
3012 // Results are undefined if min > max.
3013 if (min > max)
3014 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3015 &resultArray[i]);
3016 else
3017 resultArray[i].setFConst(gl::clamp(x, min, max));
3018 break;
3019 }
3020
3021 case EbtInt:
3022 {
3023 int x = unionArrays[0][i].getIConst();
3024 int min = unionArrays[1][i].getIConst();
3025 int max = unionArrays[2][i].getIConst();
3026 // Results are undefined if min > max.
3027 if (min > max)
3028 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3029 &resultArray[i]);
3030 else
3031 resultArray[i].setIConst(gl::clamp(x, min, max));
3032 break;
3033 }
3034 case EbtUInt:
3035 {
3036 unsigned int x = unionArrays[0][i].getUConst();
3037 unsigned int min = unionArrays[1][i].getUConst();
3038 unsigned int max = unionArrays[2][i].getUConst();
3039 // Results are undefined if min > max.
3040 if (min > max)
3041 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3042 &resultArray[i]);
3043 else
3044 resultArray[i].setUConst(gl::clamp(x, min, max));
3045 break;
3046 }
3047 default:
3048 UNREACHABLE();
3049 break;
3050 }
3051 }
3052 break;
3053 }
3054
3055 case EOpMix:
3056 {
3057 ASSERT(basicType == EbtFloat);
3058 resultArray = new TConstantUnion[maxObjectSize];
3059 for (size_t i = 0; i < maxObjectSize; i++)
3060 {
3061 float x = unionArrays[0][i].getFConst();
3062 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003063 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003064 if (type == EbtFloat)
3065 {
3066 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3067 float a = unionArrays[2][i].getFConst();
3068 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3069 }
3070 else // 3rd parameter is EbtBool
3071 {
3072 ASSERT(type == EbtBool);
3073 // Selects which vector each returned component comes from.
3074 // For a component of a that is false, the corresponding component of x is
3075 // returned.
3076 // For a component of a that is true, the corresponding component of y is
3077 // returned.
3078 bool a = unionArrays[2][i].getBConst();
3079 resultArray[i].setFConst(a ? y : x);
3080 }
3081 }
3082 break;
3083 }
3084
3085 case EOpSmoothStep:
3086 {
3087 ASSERT(basicType == EbtFloat);
3088 resultArray = new TConstantUnion[maxObjectSize];
3089 for (size_t i = 0; i < maxObjectSize; i++)
3090 {
3091 float edge0 = unionArrays[0][i].getFConst();
3092 float edge1 = unionArrays[1][i].getFConst();
3093 float x = unionArrays[2][i].getFConst();
3094 // Results are undefined if edge0 >= edge1.
3095 if (edge0 >= edge1)
3096 {
3097 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3098 }
3099 else
3100 {
3101 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3102 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3103 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3104 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3105 }
3106 }
3107 break;
3108 }
3109
Olli Etuaho74da73f2017-02-01 15:37:48 +00003110 case EOpLdexp:
3111 {
3112 resultArray = new TConstantUnion[maxObjectSize];
3113 for (size_t i = 0; i < maxObjectSize; i++)
3114 {
3115 float x = unionArrays[0][i].getFConst();
3116 int exp = unionArrays[1][i].getIConst();
3117 if (exp > 128)
3118 {
3119 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3120 }
3121 else
3122 {
3123 resultArray[i].setFConst(gl::Ldexp(x, exp));
3124 }
3125 }
3126 break;
3127 }
3128
Jamie Madille72595b2017-06-06 15:12:26 -04003129 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003130 {
3131 ASSERT(basicType == EbtFloat);
3132 // genType faceforward(genType N, genType I, genType Nref) :
3133 // If dot(Nref, I) < 0 return N, otherwise return -N.
3134 resultArray = new TConstantUnion[maxObjectSize];
3135 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3136 for (size_t i = 0; i < maxObjectSize; i++)
3137 {
3138 if (dotProduct < 0)
3139 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3140 else
3141 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3142 }
3143 break;
3144 }
3145
3146 case EOpRefract:
3147 {
3148 ASSERT(basicType == EbtFloat);
3149 // genType refract(genType I, genType N, float eta) :
3150 // For the incident vector I and surface normal N, and the ratio of indices of
3151 // refraction eta,
3152 // return the refraction vector. The result is computed by
3153 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3154 // if (k < 0.0)
3155 // return genType(0.0)
3156 // else
3157 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3158 resultArray = new TConstantUnion[maxObjectSize];
3159 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3160 for (size_t i = 0; i < maxObjectSize; i++)
3161 {
3162 float eta = unionArrays[2][i].getFConst();
3163 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3164 if (k < 0.0f)
3165 resultArray[i].setFConst(0.0f);
3166 else
3167 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3168 (eta * dotProduct + sqrtf(k)) *
3169 unionArrays[1][i].getFConst());
3170 }
3171 break;
3172 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003173 case EOpBitfieldExtract:
3174 {
3175 resultArray = new TConstantUnion[maxObjectSize];
3176 for (size_t i = 0; i < maxObjectSize; ++i)
3177 {
3178 int offset = unionArrays[1][0].getIConst();
3179 int bits = unionArrays[2][0].getIConst();
3180 if (bits == 0)
3181 {
3182 if (aggregate->getBasicType() == EbtInt)
3183 {
3184 resultArray[i].setIConst(0);
3185 }
3186 else
3187 {
3188 ASSERT(aggregate->getBasicType() == EbtUInt);
3189 resultArray[i].setUConst(0);
3190 }
3191 }
3192 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3193 {
3194 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3195 &resultArray[i]);
3196 }
3197 else
3198 {
3199 // bits can be 32 here, so we need to avoid bit shift overflow.
3200 uint32_t maskMsb = 1u << (bits - 1);
3201 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3202 if (aggregate->getBasicType() == EbtInt)
3203 {
3204 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3205 uint32_t resultUnsigned = (value & mask) >> offset;
3206 if ((resultUnsigned & maskMsb) != 0)
3207 {
3208 // The most significant bits (from bits+1 to the most significant bit)
3209 // should be set to 1.
3210 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3211 resultUnsigned |= higherBitsMask;
3212 }
3213 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3214 }
3215 else
3216 {
3217 ASSERT(aggregate->getBasicType() == EbtUInt);
3218 uint32_t value = unionArrays[0][i].getUConst();
3219 resultArray[i].setUConst((value & mask) >> offset);
3220 }
3221 }
3222 }
3223 break;
3224 }
3225 case EOpBitfieldInsert:
3226 {
3227 resultArray = new TConstantUnion[maxObjectSize];
3228 for (size_t i = 0; i < maxObjectSize; ++i)
3229 {
3230 int offset = unionArrays[2][0].getIConst();
3231 int bits = unionArrays[3][0].getIConst();
3232 if (bits == 0)
3233 {
3234 if (aggregate->getBasicType() == EbtInt)
3235 {
3236 int32_t base = unionArrays[0][i].getIConst();
3237 resultArray[i].setIConst(base);
3238 }
3239 else
3240 {
3241 ASSERT(aggregate->getBasicType() == EbtUInt);
3242 uint32_t base = unionArrays[0][i].getUConst();
3243 resultArray[i].setUConst(base);
3244 }
3245 }
3246 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3247 {
3248 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3249 &resultArray[i]);
3250 }
3251 else
3252 {
3253 // bits can be 32 here, so we need to avoid bit shift overflow.
3254 uint32_t maskMsb = 1u << (bits - 1);
3255 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3256 uint32_t baseMask = ~insertMask;
3257 if (aggregate->getBasicType() == EbtInt)
3258 {
3259 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3260 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3261 uint32_t resultUnsigned =
3262 (base & baseMask) | ((insert << offset) & insertMask);
3263 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3264 }
3265 else
3266 {
3267 ASSERT(aggregate->getBasicType() == EbtUInt);
3268 uint32_t base = unionArrays[0][i].getUConst();
3269 uint32_t insert = unionArrays[1][i].getUConst();
3270 resultArray[i].setUConst((base & baseMask) |
3271 ((insert << offset) & insertMask));
3272 }
3273 }
3274 }
3275 break;
3276 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003277
3278 default:
3279 UNREACHABLE();
3280 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303281 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003282 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303283}
3284
Jamie Madill45bcc782016-11-07 13:58:48 -05003285} // namespace sh