blob: 925e73a5eebdcf79adab3f0304cc1ec39d2df178 [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 Etuahobb2bbfb2017-08-24 15:43:33 +0300806 if (mOp == EOpArrayLength)
807 {
808 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
809 setType(TType(EbtInt, EbpUndefined, EvqConst));
810 return;
811 }
812
Olli Etuahoa2234302016-08-31 12:05:39 +0300813 TQualifier resultQualifier = EvqTemporary;
814 if (mOperand->getQualifier() == EvqConst)
815 resultQualifier = EvqConst;
816
817 unsigned char operandPrimarySize =
818 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400819 switch (mOp)
820 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300821 case EOpFloatBitsToInt:
822 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
823 break;
824 case EOpFloatBitsToUint:
825 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
826 break;
827 case EOpIntBitsToFloat:
828 case EOpUintBitsToFloat:
829 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
830 break;
831 case EOpPackSnorm2x16:
832 case EOpPackUnorm2x16:
833 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800834 case EOpPackUnorm4x8:
835 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300836 setType(TType(EbtUInt, EbpHigh, resultQualifier));
837 break;
838 case EOpUnpackSnorm2x16:
839 case EOpUnpackUnorm2x16:
840 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
841 break;
842 case EOpUnpackHalf2x16:
843 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
844 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800845 case EOpUnpackUnorm4x8:
846 case EOpUnpackSnorm4x8:
847 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
848 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300849 case EOpAny:
850 case EOpAll:
851 setType(TType(EbtBool, EbpUndefined, resultQualifier));
852 break;
853 case EOpLength:
854 case EOpDeterminant:
855 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
856 break;
857 case EOpTranspose:
858 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
859 static_cast<unsigned char>(mOperand->getType().getRows()),
860 static_cast<unsigned char>(mOperand->getType().getCols())));
861 break;
862 case EOpIsInf:
863 case EOpIsNan:
864 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
865 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000866 case EOpBitfieldReverse:
867 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
868 break;
869 case EOpBitCount:
870 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
871 break;
872 case EOpFindLSB:
873 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
874 break;
875 case EOpFindMSB:
876 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
877 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300878 default:
879 setType(mOperand->getType());
880 mType.setQualifier(resultQualifier);
881 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400882 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300883}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400884
Olli Etuahob6fa0432016-09-28 16:28:05 +0100885TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
886 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
887 mOperand(operand),
888 mSwizzleOffsets(swizzleOffsets)
889{
890 ASSERT(mSwizzleOffsets.size() <= 4);
891 promote();
892}
893
Olli Etuahoa2234302016-08-31 12:05:39 +0300894TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
895 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
896{
897 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400898}
899
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300900TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
901 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
902{
903 promote();
904}
905
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000906TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
907 : TIntermNode(), mSymbol(symbol)
908{
909 ASSERT(symbol);
910 setLine(line);
911}
912
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300913TIntermTernary::TIntermTernary(TIntermTyped *cond,
914 TIntermTyped *trueExpression,
915 TIntermTyped *falseExpression)
916 : TIntermTyped(trueExpression->getType()),
917 mCondition(cond),
918 mTrueExpression(trueExpression),
919 mFalseExpression(falseExpression)
920{
921 getTypePointer()->setQualifier(
922 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
923}
924
Olli Etuaho81629262017-04-19 11:56:01 +0300925TIntermLoop::TIntermLoop(TLoopType type,
926 TIntermNode *init,
927 TIntermTyped *cond,
928 TIntermTyped *expr,
929 TIntermBlock *body)
930 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
931{
932 // Declaration nodes with no children can appear if all the declarators just added constants to
933 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
934 if (mInit && mInit->getAsDeclarationNode() &&
935 mInit->getAsDeclarationNode()->getSequence()->empty())
936 {
937 mInit = nullptr;
938 }
939}
940
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300941// static
942TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
943 TIntermTyped *trueExpression,
944 TIntermTyped *falseExpression)
945{
946 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
947 falseExpression->getQualifier() == EvqConst)
948 {
949 return EvqConst;
950 }
951 return EvqTemporary;
952}
953
Olli Etuahoeb7f90f2017-07-07 17:25:23 +0300954TIntermTyped *TIntermTernary::fold()
955{
956 if (mCondition->getAsConstantUnion())
957 {
958 if (mCondition->getAsConstantUnion()->getBConst(0))
959 {
960 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
961 return mTrueExpression;
962 }
963 else
964 {
965 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
966 return mFalseExpression;
967 }
968 }
969 return this;
970}
971
Olli Etuahob6fa0432016-09-28 16:28:05 +0100972void TIntermSwizzle::promote()
973{
974 TQualifier resultQualifier = EvqTemporary;
975 if (mOperand->getQualifier() == EvqConst)
976 resultQualifier = EvqConst;
977
978 auto numFields = mSwizzleOffsets.size();
979 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
980 static_cast<unsigned char>(numFields)));
981}
982
983bool TIntermSwizzle::hasDuplicateOffsets() const
984{
985 int offsetCount[4] = {0u, 0u, 0u, 0u};
986 for (const auto offset : mSwizzleOffsets)
987 {
988 offsetCount[offset]++;
989 if (offsetCount[offset] > 1)
990 {
991 return true;
992 }
993 }
994 return false;
995}
996
Olli Etuaho09b04a22016-12-15 13:30:26 +0000997bool TIntermSwizzle::offsetsMatch(int offset) const
998{
999 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1000}
1001
Olli Etuahob6fa0432016-09-28 16:28:05 +01001002void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1003{
1004 for (const int offset : mSwizzleOffsets)
1005 {
1006 switch (offset)
1007 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001008 case 0:
1009 *out << "x";
1010 break;
1011 case 1:
1012 *out << "y";
1013 break;
1014 case 2:
1015 *out << "z";
1016 break;
1017 case 3:
1018 *out << "w";
1019 break;
1020 default:
1021 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001022 }
1023 }
1024}
1025
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001026TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1027 const TIntermTyped *left,
1028 const TIntermTyped *right)
1029{
1030 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1031 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1032 right->getQualifier() != EvqConst)
1033 {
1034 return EvqTemporary;
1035 }
1036 return EvqConst;
1037}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001038
1039// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001040void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001041{
Olli Etuaho1dded802016-08-18 18:13:13 +03001042 ASSERT(!isMultiplication() ||
1043 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1044
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001045 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1046 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001047 if (mOp == EOpComma)
1048 {
1049 setType(mRight->getType());
1050 return;
1051 }
1052
Jamie Madillb1a85f42014-08-19 15:23:24 -04001053 // Base assumption: just make the type the same as the left
1054 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001055 setType(mLeft->getType());
1056
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001057 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001058 // Binary operations results in temporary variables unless both
1059 // operands are const.
1060 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1061 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001062 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001063 getTypePointer()->setQualifier(EvqTemporary);
1064 }
1065
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001066 // Handle indexing ops.
1067 switch (mOp)
1068 {
1069 case EOpIndexDirect:
1070 case EOpIndexIndirect:
1071 if (mLeft->isArray())
1072 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001073 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001074 }
1075 else if (mLeft->isMatrix())
1076 {
1077 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1078 static_cast<unsigned char>(mLeft->getRows())));
1079 }
1080 else if (mLeft->isVector())
1081 {
1082 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1083 }
1084 else
1085 {
1086 UNREACHABLE();
1087 }
1088 return;
1089 case EOpIndexDirectStruct:
1090 {
1091 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1092 const int i = mRight->getAsConstantUnion()->getIConst(0);
1093 setType(*fields[i]->type());
1094 getTypePointer()->setQualifier(resultQualifier);
1095 return;
1096 }
1097 case EOpIndexDirectInterfaceBlock:
1098 {
1099 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1100 const int i = mRight->getAsConstantUnion()->getIConst(0);
1101 setType(*fields[i]->type());
1102 getTypePointer()->setQualifier(resultQualifier);
1103 return;
1104 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001105 default:
1106 break;
1107 }
1108
1109 ASSERT(mLeft->isArray() == mRight->isArray());
1110
1111 // The result gets promoted to the highest precision.
1112 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1113 getTypePointer()->setPrecision(higherPrecision);
1114
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001115 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001116
1117 //
1118 // All scalars or structs. Code after this test assumes this case is removed!
1119 //
1120 if (nominalSize == 1)
1121 {
1122 switch (mOp)
1123 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001124 //
1125 // Promote to conditional
1126 //
1127 case EOpEqual:
1128 case EOpNotEqual:
1129 case EOpLessThan:
1130 case EOpGreaterThan:
1131 case EOpLessThanEqual:
1132 case EOpGreaterThanEqual:
1133 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1134 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001135
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001136 //
1137 // And and Or operate on conditionals
1138 //
1139 case EOpLogicalAnd:
1140 case EOpLogicalXor:
1141 case EOpLogicalOr:
1142 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1143 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1144 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001145
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001146 default:
1147 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001148 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001149 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001150 }
1151
1152 // If we reach here, at least one of the operands is vector or matrix.
1153 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001154 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001155
Jamie Madillb1a85f42014-08-19 15:23:24 -04001156 switch (mOp)
1157 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001158 case EOpMul:
1159 break;
1160 case EOpMatrixTimesScalar:
1161 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001162 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001163 setType(TType(basicType, higherPrecision, resultQualifier,
1164 static_cast<unsigned char>(mRight->getCols()),
1165 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001166 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001167 break;
1168 case EOpMatrixTimesVector:
1169 setType(TType(basicType, higherPrecision, resultQualifier,
1170 static_cast<unsigned char>(mLeft->getRows()), 1));
1171 break;
1172 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001173 setType(TType(basicType, higherPrecision, resultQualifier,
1174 static_cast<unsigned char>(mRight->getCols()),
1175 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001176 break;
1177 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001178 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001179 static_cast<unsigned char>(nominalSize), 1));
1180 break;
1181 case EOpVectorTimesMatrix:
1182 setType(TType(basicType, higherPrecision, resultQualifier,
1183 static_cast<unsigned char>(mRight->getCols()), 1));
1184 break;
1185 case EOpMulAssign:
1186 case EOpVectorTimesScalarAssign:
1187 case EOpVectorTimesMatrixAssign:
1188 case EOpMatrixTimesScalarAssign:
1189 case EOpMatrixTimesMatrixAssign:
1190 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1191 break;
1192 case EOpAssign:
1193 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001194 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1195 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1196 break;
1197 case EOpAdd:
1198 case EOpSub:
1199 case EOpDiv:
1200 case EOpIMod:
1201 case EOpBitShiftLeft:
1202 case EOpBitShiftRight:
1203 case EOpBitwiseAnd:
1204 case EOpBitwiseXor:
1205 case EOpBitwiseOr:
1206 case EOpAddAssign:
1207 case EOpSubAssign:
1208 case EOpDivAssign:
1209 case EOpIModAssign:
1210 case EOpBitShiftLeftAssign:
1211 case EOpBitShiftRightAssign:
1212 case EOpBitwiseAndAssign:
1213 case EOpBitwiseXorAssign:
1214 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001215 {
1216 const int secondarySize =
1217 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1218 setType(TType(basicType, higherPrecision, resultQualifier,
1219 static_cast<unsigned char>(nominalSize),
1220 static_cast<unsigned char>(secondarySize)));
1221 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001222 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001223 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001224 case EOpEqual:
1225 case EOpNotEqual:
1226 case EOpLessThan:
1227 case EOpGreaterThan:
1228 case EOpLessThanEqual:
1229 case EOpGreaterThanEqual:
1230 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1231 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001232 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001233 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001234
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001235 case EOpIndexDirect:
1236 case EOpIndexIndirect:
1237 case EOpIndexDirectInterfaceBlock:
1238 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001239 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001240 UNREACHABLE();
1241 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001242 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001243 UNREACHABLE();
1244 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001245 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001246}
1247
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001248const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001249{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001250 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001251 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001252 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001253 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001254 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001255 size_t arrayElementSize = arrayElementType.getObjectSize();
1256 return &mUnionArrayPointer[arrayElementSize * index];
1257 }
1258 else if (isMatrix())
1259 {
1260 ASSERT(index < getType().getCols());
1261 int size = getType().getRows();
1262 return &mUnionArrayPointer[size * index];
1263 }
1264 else if (isVector())
1265 {
1266 ASSERT(index < getType().getNominalSize());
1267 return &mUnionArrayPointer[index];
1268 }
1269 else
1270 {
1271 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001272 return nullptr;
1273 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001274}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001275
Olli Etuahob6fa0432016-09-28 16:28:05 +01001276TIntermTyped *TIntermSwizzle::fold()
1277{
1278 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1279 if (operandConstant == nullptr)
1280 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001281 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001282 }
1283
1284 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1285 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1286 {
1287 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1288 }
1289 return CreateFoldedNode(constArray, this, mType.getQualifier());
1290}
1291
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001292TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1293{
1294 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1295 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1296 switch (mOp)
1297 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001298 case EOpComma:
1299 {
1300 if (mLeft->hasSideEffects())
1301 {
1302 return this;
1303 }
1304 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1305 return mRight;
1306 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001307 case EOpIndexDirect:
1308 {
1309 if (leftConstant == nullptr || rightConstant == nullptr)
1310 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001311 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001312 }
1313 int index = rightConstant->getIConst(0);
1314
1315 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001316 if (!constArray)
1317 {
1318 return this;
1319 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001320 return CreateFoldedNode(constArray, this, mType.getQualifier());
1321 }
1322 case EOpIndexDirectStruct:
1323 {
1324 if (leftConstant == nullptr || rightConstant == nullptr)
1325 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001326 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001327 }
1328 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1329 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1330
1331 size_t previousFieldsSize = 0;
1332 for (size_t i = 0; i < index; ++i)
1333 {
1334 previousFieldsSize += fields[i]->type()->getObjectSize();
1335 }
1336
1337 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1338 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1339 }
1340 case EOpIndexIndirect:
1341 case EOpIndexDirectInterfaceBlock:
1342 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001343 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001344 default:
1345 {
1346 if (leftConstant == nullptr || rightConstant == nullptr)
1347 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001348 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001349 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001350 TConstantUnion *constArray =
1351 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001352 if (!constArray)
1353 {
1354 return this;
1355 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001356
1357 // Nodes may be constant folded without being qualified as constant.
1358 return CreateFoldedNode(constArray, this, mType.getQualifier());
1359 }
1360 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001361}
1362
Olli Etuahof119a262016-08-19 15:54:22 +03001363TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001364{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301365 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001366
1367 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301368 {
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001369 if (mOperand->hasSideEffects())
1370 {
1371 return this;
1372 }
1373 constArray = new TConstantUnion[1];
1374 constArray->setIConst(mOperand->getOutermostArraySize());
1375 }
1376 else
1377 {
1378 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1379 if (operandConstant == nullptr)
1380 {
1381 return this;
1382 }
1383
1384 switch (mOp)
1385 {
1386 case EOpAny:
1387 case EOpAll:
1388 case EOpLength:
1389 case EOpTranspose:
1390 case EOpDeterminant:
1391 case EOpInverse:
1392 case EOpPackSnorm2x16:
1393 case EOpUnpackSnorm2x16:
1394 case EOpPackUnorm2x16:
1395 case EOpUnpackUnorm2x16:
1396 case EOpPackHalf2x16:
1397 case EOpUnpackHalf2x16:
1398 case EOpPackUnorm4x8:
1399 case EOpPackSnorm4x8:
1400 case EOpUnpackUnorm4x8:
1401 case EOpUnpackSnorm4x8:
1402 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1403 break;
1404 default:
1405 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1406 break;
1407 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301408 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001409 if (constArray == nullptr)
1410 {
1411 return this;
1412 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001413
1414 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001415 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001416}
1417
Olli Etuahof119a262016-08-19 15:54:22 +03001418TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001419{
1420 // Make sure that all params are constant before actual constant folding.
1421 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001422 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001423 if (param->getAsConstantUnion() == nullptr)
1424 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001425 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001426 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001427 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001428 TConstantUnion *constArray = nullptr;
1429 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001430 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001431 else
Olli Etuahof119a262016-08-19 15:54:22 +03001432 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001433
1434 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001435 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001436}
1437
Jamie Madillb1a85f42014-08-19 15:23:24 -04001438//
1439// The fold functions see if an operation on a constant can be done in place,
1440// without generating run-time code.
1441//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001442// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001443//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001444TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1445 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001446 TDiagnostics *diagnostics,
1447 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001448{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001449 const TConstantUnion *leftArray = getUnionArrayPointer();
1450 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001451
Olli Etuahof119a262016-08-19 15:54:22 +03001452 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001453
1454 size_t objectSize = getType().getObjectSize();
1455
1456 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1457 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1458 {
1459 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1460 }
1461 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1462 {
1463 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001464 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001465 objectSize = rightNode->getType().getObjectSize();
1466 }
1467
1468 TConstantUnion *resultArray = nullptr;
1469
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001470 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001471 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001472 case EOpAdd:
1473 resultArray = new TConstantUnion[objectSize];
1474 for (size_t i = 0; i < objectSize; i++)
1475 resultArray[i] =
1476 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1477 break;
1478 case EOpSub:
1479 resultArray = new TConstantUnion[objectSize];
1480 for (size_t i = 0; i < objectSize; i++)
1481 resultArray[i] =
1482 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1483 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001484
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001485 case EOpMul:
1486 case EOpVectorTimesScalar:
1487 case EOpMatrixTimesScalar:
1488 resultArray = new TConstantUnion[objectSize];
1489 for (size_t i = 0; i < objectSize; i++)
1490 resultArray[i] =
1491 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1492 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001493
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001494 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001495 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001496 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001497 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001498
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001499 const int leftCols = getCols();
1500 const int leftRows = getRows();
1501 const int rightCols = rightNode->getType().getCols();
1502 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001503 const int resultCols = rightCols;
1504 const int resultRows = leftRows;
1505
1506 resultArray = new TConstantUnion[resultCols * resultRows];
1507 for (int row = 0; row < resultRows; row++)
1508 {
1509 for (int column = 0; column < resultCols; column++)
1510 {
1511 resultArray[resultRows * column + row].setFConst(0.0f);
1512 for (int i = 0; i < leftCols; i++)
1513 {
1514 resultArray[resultRows * column + row].setFConst(
1515 resultArray[resultRows * column + row].getFConst() +
1516 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001517 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001518 }
1519 }
1520 }
1521 }
1522 break;
1523
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001524 case EOpDiv:
1525 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001526 {
1527 resultArray = new TConstantUnion[objectSize];
1528 for (size_t i = 0; i < objectSize; i++)
1529 {
1530 switch (getType().getBasicType())
1531 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001532 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001533 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001534 ASSERT(op == EOpDiv);
1535 float dividend = leftArray[i].getFConst();
1536 float divisor = rightArray[i].getFConst();
1537 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001538 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001539 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001540 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001541 diagnostics->warning(
1542 getLine(),
1543 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001544 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001545 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001546 }
1547 else
1548 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001549 diagnostics->warning(getLine(),
1550 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001551 bool negativeResult =
1552 std::signbit(dividend) != std::signbit(divisor);
1553 resultArray[i].setFConst(
1554 negativeResult ? -std::numeric_limits<float>::infinity()
1555 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001556 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001557 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001558 else if (gl::isInf(dividend) && gl::isInf(divisor))
1559 {
1560 diagnostics->warning(getLine(),
1561 "Infinity divided by infinity during constant "
1562 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001563 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001564 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1565 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001566 else
1567 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001568 float result = dividend / divisor;
1569 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001570 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001571 diagnostics->warning(
1572 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001573 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001574 }
1575 resultArray[i].setFConst(result);
1576 }
1577 break;
1578 }
1579 case EbtInt:
1580 if (rightArray[i] == 0)
1581 {
1582 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001583 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001584 resultArray[i].setIConst(INT_MAX);
1585 }
1586 else
1587 {
1588 int lhs = leftArray[i].getIConst();
1589 int divisor = rightArray[i].getIConst();
1590 if (op == EOpDiv)
1591 {
1592 // Check for the special case where the minimum representable number
1593 // is
1594 // divided by -1. If left alone this leads to integer overflow in
1595 // C++.
1596 // ESSL 3.00.6 section 4.1.3 Integers:
1597 // "However, for the case where the minimum representable value is
1598 // divided by -1, it is allowed to return either the minimum
1599 // representable value or the maximum representable value."
1600 if (lhs == -0x7fffffff - 1 && divisor == -1)
1601 {
1602 resultArray[i].setIConst(0x7fffffff);
1603 }
1604 else
1605 {
1606 resultArray[i].setIConst(lhs / divisor);
1607 }
Olli Etuahod4453572016-09-27 13:21:46 +01001608 }
1609 else
1610 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001611 ASSERT(op == EOpIMod);
1612 if (lhs < 0 || divisor < 0)
1613 {
1614 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1615 // when
1616 // either one of the operands is negative.
1617 diagnostics->warning(getLine(),
1618 "Negative modulus operator operand "
1619 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001620 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001621 resultArray[i].setIConst(0);
1622 }
1623 else
1624 {
1625 resultArray[i].setIConst(lhs % divisor);
1626 }
Olli Etuahod4453572016-09-27 13:21:46 +01001627 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001628 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001629 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001630
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001631 case EbtUInt:
1632 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001633 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001634 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001635 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001636 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001637 }
1638 else
1639 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001640 if (op == EOpDiv)
1641 {
1642 resultArray[i].setUConst(leftArray[i].getUConst() /
1643 rightArray[i].getUConst());
1644 }
1645 else
1646 {
1647 ASSERT(op == EOpIMod);
1648 resultArray[i].setUConst(leftArray[i].getUConst() %
1649 rightArray[i].getUConst());
1650 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001651 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001652 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001653
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001654 default:
1655 UNREACHABLE();
1656 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001657 }
1658 }
1659 }
1660 break;
1661
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001662 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001663 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001664 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001665 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001666
1667 const int matrixCols = getCols();
1668 const int matrixRows = getRows();
1669
1670 resultArray = new TConstantUnion[matrixRows];
1671
1672 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1673 {
1674 resultArray[matrixRow].setFConst(0.0f);
1675 for (int col = 0; col < matrixCols; col++)
1676 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001677 resultArray[matrixRow].setFConst(
1678 resultArray[matrixRow].getFConst() +
1679 leftArray[col * matrixRows + matrixRow].getFConst() *
1680 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001681 }
1682 }
1683 }
1684 break;
1685
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001686 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001687 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001688 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001689 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001690
1691 const int matrixCols = rightNode->getType().getCols();
1692 const int matrixRows = rightNode->getType().getRows();
1693
1694 resultArray = new TConstantUnion[matrixCols];
1695
1696 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1697 {
1698 resultArray[matrixCol].setFConst(0.0f);
1699 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1700 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001701 resultArray[matrixCol].setFConst(
1702 resultArray[matrixCol].getFConst() +
1703 leftArray[matrixRow].getFConst() *
1704 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001705 }
1706 }
1707 }
1708 break;
1709
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001710 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001711 {
1712 resultArray = new TConstantUnion[objectSize];
1713 for (size_t i = 0; i < objectSize; i++)
1714 {
1715 resultArray[i] = leftArray[i] && rightArray[i];
1716 }
1717 }
1718 break;
1719
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001720 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001721 {
1722 resultArray = new TConstantUnion[objectSize];
1723 for (size_t i = 0; i < objectSize; i++)
1724 {
1725 resultArray[i] = leftArray[i] || rightArray[i];
1726 }
1727 }
1728 break;
1729
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001730 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001731 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001732 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001733 resultArray = new TConstantUnion[objectSize];
1734 for (size_t i = 0; i < objectSize; i++)
1735 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001736 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001737 }
1738 }
1739 break;
1740
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001741 case EOpBitwiseAnd:
1742 resultArray = new TConstantUnion[objectSize];
1743 for (size_t i = 0; i < objectSize; i++)
1744 resultArray[i] = leftArray[i] & rightArray[i];
1745 break;
1746 case EOpBitwiseXor:
1747 resultArray = new TConstantUnion[objectSize];
1748 for (size_t i = 0; i < objectSize; i++)
1749 resultArray[i] = leftArray[i] ^ rightArray[i];
1750 break;
1751 case EOpBitwiseOr:
1752 resultArray = new TConstantUnion[objectSize];
1753 for (size_t i = 0; i < objectSize; i++)
1754 resultArray[i] = leftArray[i] | rightArray[i];
1755 break;
1756 case EOpBitShiftLeft:
1757 resultArray = new TConstantUnion[objectSize];
1758 for (size_t i = 0; i < objectSize; i++)
1759 resultArray[i] =
1760 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1761 break;
1762 case EOpBitShiftRight:
1763 resultArray = new TConstantUnion[objectSize];
1764 for (size_t i = 0; i < objectSize; i++)
1765 resultArray[i] =
1766 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1767 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001768
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001769 case EOpLessThan:
1770 ASSERT(objectSize == 1);
1771 resultArray = new TConstantUnion[1];
1772 resultArray->setBConst(*leftArray < *rightArray);
1773 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001774
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001775 case EOpGreaterThan:
1776 ASSERT(objectSize == 1);
1777 resultArray = new TConstantUnion[1];
1778 resultArray->setBConst(*leftArray > *rightArray);
1779 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001780
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001781 case EOpLessThanEqual:
1782 ASSERT(objectSize == 1);
1783 resultArray = new TConstantUnion[1];
1784 resultArray->setBConst(!(*leftArray > *rightArray));
1785 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001786
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001787 case EOpGreaterThanEqual:
1788 ASSERT(objectSize == 1);
1789 resultArray = new TConstantUnion[1];
1790 resultArray->setBConst(!(*leftArray < *rightArray));
1791 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001792
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001793 case EOpEqual:
1794 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001795 {
1796 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001797 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001798 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001799 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001800 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001801 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001802 equal = false;
1803 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001804 }
1805 }
1806 if (op == EOpEqual)
1807 {
1808 resultArray->setBConst(equal);
1809 }
1810 else
1811 {
1812 resultArray->setBConst(!equal);
1813 }
1814 }
1815 break;
1816
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001817 default:
1818 UNREACHABLE();
1819 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001820 }
1821 return resultArray;
1822}
1823
Olli Etuahof119a262016-08-19 15:54:22 +03001824// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1825// code. Returns the constant value to keep using. Nullptr should not be returned.
1826TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001827{
Olli Etuahof119a262016-08-19 15:54:22 +03001828 // Do operations where the return type may have a different number of components compared to the
1829 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001830
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001831 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001832 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301833
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001834 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301835 TConstantUnion *resultArray = nullptr;
1836 switch (op)
1837 {
Olli Etuahof119a262016-08-19 15:54:22 +03001838 case EOpAny:
1839 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301840 resultArray = new TConstantUnion();
1841 resultArray->setBConst(false);
1842 for (size_t i = 0; i < objectSize; i++)
1843 {
1844 if (operandArray[i].getBConst())
1845 {
1846 resultArray->setBConst(true);
1847 break;
1848 }
1849 }
1850 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301851
Olli Etuahof119a262016-08-19 15:54:22 +03001852 case EOpAll:
1853 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301854 resultArray = new TConstantUnion();
1855 resultArray->setBConst(true);
1856 for (size_t i = 0; i < objectSize; i++)
1857 {
1858 if (!operandArray[i].getBConst())
1859 {
1860 resultArray->setBConst(false);
1861 break;
1862 }
1863 }
1864 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301865
Olli Etuahof119a262016-08-19 15:54:22 +03001866 case EOpLength:
1867 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301868 resultArray = new TConstantUnion();
1869 resultArray->setFConst(VectorLength(operandArray, objectSize));
1870 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301871
Olli Etuahof119a262016-08-19 15:54:22 +03001872 case EOpTranspose:
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 resultArray = new TConstantUnion[objectSize];
1876 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001877 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301878 SetUnionArrayFromMatrix(result, resultArray);
1879 break;
1880 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301881
Olli Etuahof119a262016-08-19 15:54:22 +03001882 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301883 {
Olli Etuahof119a262016-08-19 15:54:22 +03001884 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301885 unsigned int size = getType().getNominalSize();
1886 ASSERT(size >= 2 && size <= 4);
1887 resultArray = new TConstantUnion();
1888 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1889 break;
1890 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301891
Olli Etuahof119a262016-08-19 15:54:22 +03001892 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301893 {
Olli Etuahof119a262016-08-19 15:54:22 +03001894 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301895 unsigned int size = getType().getNominalSize();
1896 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001897 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301898 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1899 SetUnionArrayFromMatrix(result, resultArray);
1900 break;
1901 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301902
Olli Etuahof119a262016-08-19 15:54:22 +03001903 case EOpPackSnorm2x16:
1904 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301905 ASSERT(getType().getNominalSize() == 2);
1906 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001907 resultArray->setUConst(
1908 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301909 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301910
Olli Etuahof119a262016-08-19 15:54:22 +03001911 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301912 {
Olli Etuahof119a262016-08-19 15:54:22 +03001913 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301914 resultArray = new TConstantUnion[2];
1915 float f1, f2;
1916 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1917 resultArray[0].setFConst(f1);
1918 resultArray[1].setFConst(f2);
1919 break;
1920 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301921
Olli Etuahof119a262016-08-19 15:54:22 +03001922 case EOpPackUnorm2x16:
1923 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301924 ASSERT(getType().getNominalSize() == 2);
1925 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001926 resultArray->setUConst(
1927 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301928 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301929
Olli Etuahof119a262016-08-19 15:54:22 +03001930 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301931 {
Olli Etuahof119a262016-08-19 15:54:22 +03001932 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301933 resultArray = new TConstantUnion[2];
1934 float f1, f2;
1935 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1936 resultArray[0].setFConst(f1);
1937 resultArray[1].setFConst(f2);
1938 break;
1939 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301940
Olli Etuahof119a262016-08-19 15:54:22 +03001941 case EOpPackHalf2x16:
1942 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301943 ASSERT(getType().getNominalSize() == 2);
1944 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001945 resultArray->setUConst(
1946 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301947 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301948
Olli Etuahof119a262016-08-19 15:54:22 +03001949 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301950 {
Olli Etuahof119a262016-08-19 15:54:22 +03001951 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301952 resultArray = new TConstantUnion[2];
1953 float f1, f2;
1954 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1955 resultArray[0].setFConst(f1);
1956 resultArray[1].setFConst(f2);
1957 break;
1958 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301959
Olli Etuaho25aef452017-01-29 16:15:44 -08001960 case EOpPackUnorm4x8:
1961 {
1962 ASSERT(getType().getBasicType() == EbtFloat);
1963 resultArray = new TConstantUnion();
1964 resultArray->setUConst(
1965 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1966 operandArray[2].getFConst(), operandArray[3].getFConst()));
1967 break;
1968 }
1969 case EOpPackSnorm4x8:
1970 {
1971 ASSERT(getType().getBasicType() == EbtFloat);
1972 resultArray = new TConstantUnion();
1973 resultArray->setUConst(
1974 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1975 operandArray[2].getFConst(), operandArray[3].getFConst()));
1976 break;
1977 }
1978 case EOpUnpackUnorm4x8:
1979 {
1980 ASSERT(getType().getBasicType() == EbtUInt);
1981 resultArray = new TConstantUnion[4];
1982 float f[4];
1983 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
1984 for (size_t i = 0; i < 4; ++i)
1985 {
1986 resultArray[i].setFConst(f[i]);
1987 }
1988 break;
1989 }
1990 case EOpUnpackSnorm4x8:
1991 {
1992 ASSERT(getType().getBasicType() == EbtUInt);
1993 resultArray = new TConstantUnion[4];
1994 float f[4];
1995 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
1996 for (size_t i = 0; i < 4; ++i)
1997 {
1998 resultArray[i].setFConst(f[i]);
1999 }
2000 break;
2001 }
2002
Olli Etuahof119a262016-08-19 15:54:22 +03002003 default:
2004 UNREACHABLE();
2005 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302006 }
2007
2008 return resultArray;
2009}
2010
Olli Etuahof119a262016-08-19 15:54:22 +03002011TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2012 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302013{
Olli Etuahof119a262016-08-19 15:54:22 +03002014 // Do unary operations where each component of the result is computed based on the corresponding
2015 // component of the operand. Also folds normalize, though the divisor in that case takes all
2016 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302017
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002018 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002019 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002020
2021 size_t objectSize = getType().getObjectSize();
2022
Arun Patoleab2b9a22015-07-06 18:27:56 +05302023 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2024 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302025 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002026 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302027 {
Olli Etuahof119a262016-08-19 15:54:22 +03002028 case EOpNegative:
2029 switch (getType().getBasicType())
2030 {
2031 case EbtFloat:
2032 resultArray[i].setFConst(-operandArray[i].getFConst());
2033 break;
2034 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002035 if (operandArray[i] == std::numeric_limits<int>::min())
2036 {
2037 // The minimum representable integer doesn't have a positive
2038 // counterpart, rather the negation overflows and in ESSL is supposed to
2039 // wrap back to the minimum representable integer. Make sure that we
2040 // don't actually let the negation overflow, which has undefined
2041 // behavior in C++.
2042 resultArray[i].setIConst(std::numeric_limits<int>::min());
2043 }
2044 else
2045 {
2046 resultArray[i].setIConst(-operandArray[i].getIConst());
2047 }
Olli Etuahof119a262016-08-19 15:54:22 +03002048 break;
2049 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002050 if (operandArray[i] == 0x80000000u)
2051 {
2052 resultArray[i].setUConst(0x80000000u);
2053 }
2054 else
2055 {
2056 resultArray[i].setUConst(static_cast<unsigned int>(
2057 -static_cast<int>(operandArray[i].getUConst())));
2058 }
Olli Etuahof119a262016-08-19 15:54:22 +03002059 break;
2060 default:
2061 UNREACHABLE();
2062 return nullptr;
2063 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302064 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302065
Olli Etuahof119a262016-08-19 15:54:22 +03002066 case EOpPositive:
2067 switch (getType().getBasicType())
2068 {
2069 case EbtFloat:
2070 resultArray[i].setFConst(operandArray[i].getFConst());
2071 break;
2072 case EbtInt:
2073 resultArray[i].setIConst(operandArray[i].getIConst());
2074 break;
2075 case EbtUInt:
2076 resultArray[i].setUConst(static_cast<unsigned int>(
2077 static_cast<int>(operandArray[i].getUConst())));
2078 break;
2079 default:
2080 UNREACHABLE();
2081 return nullptr;
2082 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302083 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302084
Olli Etuahof119a262016-08-19 15:54:22 +03002085 case EOpLogicalNot:
2086 switch (getType().getBasicType())
2087 {
2088 case EbtBool:
2089 resultArray[i].setBConst(!operandArray[i].getBConst());
2090 break;
2091 default:
2092 UNREACHABLE();
2093 return nullptr;
2094 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302095 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302096
Olli Etuahof119a262016-08-19 15:54:22 +03002097 case EOpBitwiseNot:
2098 switch (getType().getBasicType())
2099 {
2100 case EbtInt:
2101 resultArray[i].setIConst(~operandArray[i].getIConst());
2102 break;
2103 case EbtUInt:
2104 resultArray[i].setUConst(~operandArray[i].getUConst());
2105 break;
2106 default:
2107 UNREACHABLE();
2108 return nullptr;
2109 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302110 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302111
Olli Etuahof119a262016-08-19 15:54:22 +03002112 case EOpRadians:
2113 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302114 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2115 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302116
Olli Etuahof119a262016-08-19 15:54:22 +03002117 case EOpDegrees:
2118 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302119 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2120 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302121
Olli Etuahof119a262016-08-19 15:54:22 +03002122 case EOpSin:
2123 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302124 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302125
Olli Etuahof119a262016-08-19 15:54:22 +03002126 case EOpCos:
2127 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2128 break;
2129
2130 case EOpTan:
2131 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2132 break;
2133
2134 case EOpAsin:
2135 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2136 // 0.
2137 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2138 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2139 diagnostics, &resultArray[i]);
2140 else
2141 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2142 break;
2143
2144 case EOpAcos:
2145 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2146 // 0.
2147 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2148 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2149 diagnostics, &resultArray[i]);
2150 else
2151 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2152 break;
2153
2154 case EOpAtan:
2155 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2156 break;
2157
2158 case EOpSinh:
2159 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2160 break;
2161
2162 case EOpCosh:
2163 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2164 break;
2165
2166 case EOpTanh:
2167 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2168 break;
2169
2170 case EOpAsinh:
2171 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2172 break;
2173
2174 case EOpAcosh:
2175 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2176 if (operandArray[i].getFConst() < 1.0f)
2177 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2178 diagnostics, &resultArray[i]);
2179 else
2180 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2181 break;
2182
2183 case EOpAtanh:
2184 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2185 // 0.
2186 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2187 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2188 diagnostics, &resultArray[i]);
2189 else
2190 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2191 break;
2192
2193 case EOpAbs:
2194 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302195 {
Olli Etuahof119a262016-08-19 15:54:22 +03002196 case EbtFloat:
2197 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2198 break;
2199 case EbtInt:
2200 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2201 break;
2202 default:
2203 UNREACHABLE();
2204 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302205 }
2206 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002207
2208 case EOpSign:
2209 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302210 {
Olli Etuahof119a262016-08-19 15:54:22 +03002211 case EbtFloat:
2212 {
2213 float fConst = operandArray[i].getFConst();
2214 float fResult = 0.0f;
2215 if (fConst > 0.0f)
2216 fResult = 1.0f;
2217 else if (fConst < 0.0f)
2218 fResult = -1.0f;
2219 resultArray[i].setFConst(fResult);
2220 break;
2221 }
2222 case EbtInt:
2223 {
2224 int iConst = operandArray[i].getIConst();
2225 int iResult = 0;
2226 if (iConst > 0)
2227 iResult = 1;
2228 else if (iConst < 0)
2229 iResult = -1;
2230 resultArray[i].setIConst(iResult);
2231 break;
2232 }
2233 default:
2234 UNREACHABLE();
2235 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302236 }
2237 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302238
Olli Etuahof119a262016-08-19 15:54:22 +03002239 case EOpFloor:
2240 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2241 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302242
Olli Etuahof119a262016-08-19 15:54:22 +03002243 case EOpTrunc:
2244 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2245 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302246
Olli Etuahof119a262016-08-19 15:54:22 +03002247 case EOpRound:
2248 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2249 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302250
Olli Etuahof119a262016-08-19 15:54:22 +03002251 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302252 {
Olli Etuahof119a262016-08-19 15:54:22 +03002253 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302254 float x = operandArray[i].getFConst();
2255 float result;
2256 float fractPart = modff(x, &result);
2257 if (fabsf(fractPart) == 0.5f)
2258 result = 2.0f * roundf(x / 2.0f);
2259 else
2260 result = roundf(x);
2261 resultArray[i].setFConst(result);
2262 break;
2263 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302264
Olli Etuahof119a262016-08-19 15:54:22 +03002265 case EOpCeil:
2266 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2267 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302268
Olli Etuahof119a262016-08-19 15:54:22 +03002269 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302270 {
Olli Etuahof119a262016-08-19 15:54:22 +03002271 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302272 float x = operandArray[i].getFConst();
2273 resultArray[i].setFConst(x - floorf(x));
2274 break;
2275 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302276
Olli Etuahof119a262016-08-19 15:54:22 +03002277 case EOpIsNan:
2278 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302279 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2280 break;
Arun Patole551279e2015-07-07 18:18:23 +05302281
Olli Etuahof119a262016-08-19 15:54:22 +03002282 case EOpIsInf:
2283 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302284 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2285 break;
Arun Patole551279e2015-07-07 18:18:23 +05302286
Olli Etuahof119a262016-08-19 15:54:22 +03002287 case EOpFloatBitsToInt:
2288 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302289 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2290 break;
Arun Patole551279e2015-07-07 18:18:23 +05302291
Olli Etuahof119a262016-08-19 15:54:22 +03002292 case EOpFloatBitsToUint:
2293 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302294 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2295 break;
Arun Patole551279e2015-07-07 18:18:23 +05302296
Olli Etuahof119a262016-08-19 15:54:22 +03002297 case EOpIntBitsToFloat:
2298 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302299 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2300 break;
Arun Patole551279e2015-07-07 18:18:23 +05302301
Olli Etuahof119a262016-08-19 15:54:22 +03002302 case EOpUintBitsToFloat:
2303 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302304 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2305 break;
Arun Patole551279e2015-07-07 18:18:23 +05302306
Olli Etuahof119a262016-08-19 15:54:22 +03002307 case EOpExp:
2308 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2309 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302310
Olli Etuahof119a262016-08-19 15:54:22 +03002311 case EOpLog:
2312 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2313 if (operandArray[i].getFConst() <= 0.0f)
2314 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2315 diagnostics, &resultArray[i]);
2316 else
2317 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2318 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302319
Olli Etuahof119a262016-08-19 15:54:22 +03002320 case EOpExp2:
2321 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2322 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302323
Olli Etuahof119a262016-08-19 15:54:22 +03002324 case EOpLog2:
2325 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2326 // And log2f is not available on some plarforms like old android, so just using
2327 // log(x)/log(2) here.
2328 if (operandArray[i].getFConst() <= 0.0f)
2329 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2330 diagnostics, &resultArray[i]);
2331 else
2332 {
2333 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2334 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2335 }
2336 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302337
Olli Etuahof119a262016-08-19 15:54:22 +03002338 case EOpSqrt:
2339 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2340 if (operandArray[i].getFConst() < 0.0f)
2341 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2342 diagnostics, &resultArray[i]);
2343 else
2344 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2345 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302346
Olli Etuahof119a262016-08-19 15:54:22 +03002347 case EOpInverseSqrt:
2348 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2349 // so getting the square root first using builtin function sqrt() and then taking
2350 // its inverse.
2351 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2352 // result to 0.
2353 if (operandArray[i].getFConst() <= 0.0f)
2354 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2355 diagnostics, &resultArray[i]);
2356 else
2357 {
2358 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2359 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2360 }
2361 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302362
Olli Etuahod68924e2017-01-02 17:34:40 +00002363 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002364 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302365 resultArray[i].setBConst(!operandArray[i].getBConst());
2366 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302367
Olli Etuahof119a262016-08-19 15:54:22 +03002368 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302369 {
Olli Etuahof119a262016-08-19 15:54:22 +03002370 ASSERT(getType().getBasicType() == EbtFloat);
2371 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302372 float length = VectorLength(operandArray, objectSize);
2373 if (length)
2374 resultArray[i].setFConst(x / length);
2375 else
Olli Etuahof119a262016-08-19 15:54:22 +03002376 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2377 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302378 break;
2379 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002380 case EOpBitfieldReverse:
2381 {
2382 uint32_t value;
2383 if (getType().getBasicType() == EbtInt)
2384 {
2385 value = static_cast<uint32_t>(operandArray[i].getIConst());
2386 }
2387 else
2388 {
2389 ASSERT(getType().getBasicType() == EbtUInt);
2390 value = operandArray[i].getUConst();
2391 }
2392 uint32_t result = gl::BitfieldReverse(value);
2393 if (getType().getBasicType() == EbtInt)
2394 {
2395 resultArray[i].setIConst(static_cast<int32_t>(result));
2396 }
2397 else
2398 {
2399 resultArray[i].setUConst(result);
2400 }
2401 break;
2402 }
2403 case EOpBitCount:
2404 {
2405 uint32_t value;
2406 if (getType().getBasicType() == EbtInt)
2407 {
2408 value = static_cast<uint32_t>(operandArray[i].getIConst());
2409 }
2410 else
2411 {
2412 ASSERT(getType().getBasicType() == EbtUInt);
2413 value = operandArray[i].getUConst();
2414 }
2415 int result = gl::BitCount(value);
2416 resultArray[i].setIConst(result);
2417 break;
2418 }
2419 case EOpFindLSB:
2420 {
2421 uint32_t value;
2422 if (getType().getBasicType() == EbtInt)
2423 {
2424 value = static_cast<uint32_t>(operandArray[i].getIConst());
2425 }
2426 else
2427 {
2428 ASSERT(getType().getBasicType() == EbtUInt);
2429 value = operandArray[i].getUConst();
2430 }
2431 resultArray[i].setIConst(gl::FindLSB(value));
2432 break;
2433 }
2434 case EOpFindMSB:
2435 {
2436 uint32_t value;
2437 if (getType().getBasicType() == EbtInt)
2438 {
2439 int intValue = operandArray[i].getIConst();
2440 value = static_cast<uint32_t>(intValue);
2441 if (intValue < 0)
2442 {
2443 // Look for zero instead of one in value. This also handles the intValue ==
2444 // -1 special case, where the return value needs to be -1.
2445 value = ~value;
2446 }
2447 }
2448 else
2449 {
2450 ASSERT(getType().getBasicType() == EbtUInt);
2451 value = operandArray[i].getUConst();
2452 }
2453 resultArray[i].setIConst(gl::FindMSB(value));
2454 break;
2455 }
Olli Etuahof119a262016-08-19 15:54:22 +03002456 case EOpDFdx:
2457 case EOpDFdy:
2458 case EOpFwidth:
2459 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302460 // Derivatives of constant arguments should be 0.
2461 resultArray[i].setFConst(0.0f);
2462 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302463
Olli Etuahof119a262016-08-19 15:54:22 +03002464 default:
2465 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302466 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302467 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002468
Arun Patoleab2b9a22015-07-06 18:27:56 +05302469 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002470}
2471
Olli Etuahof119a262016-08-19 15:54:22 +03002472void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2473 FloatTypeUnaryFunc builtinFunc,
2474 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302475{
2476 ASSERT(builtinFunc);
2477
Olli Etuahof119a262016-08-19 15:54:22 +03002478 ASSERT(getType().getBasicType() == EbtFloat);
2479 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302480}
2481
Jamie Madillb1a85f42014-08-19 15:23:24 -04002482// static
Olli Etuahof119a262016-08-19 15:54:22 +03002483TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002484{
2485 ASSERT(aggregate->getSequence()->size() > 0u);
2486 size_t resultSize = aggregate->getType().getObjectSize();
2487 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2488 TBasicType basicType = aggregate->getBasicType();
2489
2490 size_t resultIndex = 0u;
2491
2492 if (aggregate->getSequence()->size() == 1u)
2493 {
2494 TIntermNode *argument = aggregate->getSequence()->front();
2495 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2496 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2497 // Check the special case of constructing a matrix diagonal from a single scalar,
2498 // or a vector from a single scalar.
2499 if (argumentConstant->getType().getObjectSize() == 1u)
2500 {
2501 if (aggregate->isMatrix())
2502 {
2503 int resultCols = aggregate->getType().getCols();
2504 int resultRows = aggregate->getType().getRows();
2505 for (int col = 0; col < resultCols; ++col)
2506 {
2507 for (int row = 0; row < resultRows; ++row)
2508 {
2509 if (col == row)
2510 {
2511 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2512 }
2513 else
2514 {
2515 resultArray[resultIndex].setFConst(0.0f);
2516 }
2517 ++resultIndex;
2518 }
2519 }
2520 }
2521 else
2522 {
2523 while (resultIndex < resultSize)
2524 {
2525 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2526 ++resultIndex;
2527 }
2528 }
2529 ASSERT(resultIndex == resultSize);
2530 return resultArray;
2531 }
2532 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2533 {
2534 // The special case of constructing a matrix from a matrix.
2535 int argumentCols = argumentConstant->getType().getCols();
2536 int argumentRows = argumentConstant->getType().getRows();
2537 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002538 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002539 for (int col = 0; col < resultCols; ++col)
2540 {
2541 for (int row = 0; row < resultRows; ++row)
2542 {
2543 if (col < argumentCols && row < argumentRows)
2544 {
2545 resultArray[resultIndex].cast(basicType,
2546 argumentUnionArray[col * argumentRows + row]);
2547 }
2548 else if (col == row)
2549 {
2550 resultArray[resultIndex].setFConst(1.0f);
2551 }
2552 else
2553 {
2554 resultArray[resultIndex].setFConst(0.0f);
2555 }
2556 ++resultIndex;
2557 }
2558 }
2559 ASSERT(resultIndex == resultSize);
2560 return resultArray;
2561 }
2562 }
2563
2564 for (TIntermNode *&argument : *aggregate->getSequence())
2565 {
2566 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2567 size_t argumentSize = argumentConstant->getType().getObjectSize();
2568 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2569 for (size_t i = 0u; i < argumentSize; ++i)
2570 {
2571 if (resultIndex >= resultSize)
2572 break;
2573 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2574 ++resultIndex;
2575 }
2576 }
2577 ASSERT(resultIndex == resultSize);
2578 return resultArray;
2579}
2580
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002581bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2582{
2583 switch (op)
2584 {
2585 case EOpAtan:
2586 case EOpPow:
2587 case EOpMod:
2588 case EOpMin:
2589 case EOpMax:
2590 case EOpClamp:
2591 case EOpMix:
2592 case EOpStep:
2593 case EOpSmoothStep:
2594 case EOpLdexp:
2595 case EOpMulMatrixComponentWise:
2596 case EOpOuterProduct:
2597 case EOpEqualComponentWise:
2598 case EOpNotEqualComponentWise:
2599 case EOpLessThanComponentWise:
2600 case EOpLessThanEqualComponentWise:
2601 case EOpGreaterThanComponentWise:
2602 case EOpGreaterThanEqualComponentWise:
2603 case EOpDistance:
2604 case EOpDot:
2605 case EOpCross:
2606 case EOpFaceforward:
2607 case EOpReflect:
2608 case EOpRefract:
2609 case EOpBitfieldExtract:
2610 case EOpBitfieldInsert:
2611 return true;
2612 default:
2613 return false;
2614 }
2615}
2616
Olli Etuaho1d122782015-11-06 15:35:17 +02002617// static
Olli Etuahof119a262016-08-19 15:54:22 +03002618TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2619 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302620{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002621 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002622 TIntermSequence *arguments = aggregate->getSequence();
2623 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2624 std::vector<const TConstantUnion *> unionArrays(argsCount);
2625 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002626 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302627 TBasicType basicType = EbtVoid;
2628 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002629 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302630 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002631 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2632 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302633
2634 if (i == 0)
2635 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002636 basicType = argConstant->getType().getBasicType();
2637 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302638 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002639 unionArrays[i] = argConstant->getUnionArrayPointer();
2640 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002641 if (objectSizes[i] > maxObjectSize)
2642 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302643 }
2644
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002645 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302646 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002647 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302648 if (objectSizes[i] != maxObjectSize)
2649 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2650 }
Arun Patole274f0702015-05-05 13:33:30 +05302651
Olli Etuahob43846e2015-06-02 18:18:57 +03002652 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002653
2654 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302655 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002656 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302657 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002658 ASSERT(basicType == EbtFloat);
2659 resultArray = new TConstantUnion[maxObjectSize];
2660 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302661 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002662 float y = unionArrays[0][i].getFConst();
2663 float x = unionArrays[1][i].getFConst();
2664 // Results are undefined if x and y are both 0.
2665 if (x == 0.0f && y == 0.0f)
2666 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2667 else
2668 resultArray[i].setFConst(atan2f(y, x));
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 EOpPow:
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 // Results are undefined if x < 0.
2682 // Results are undefined if x = 0 and y <= 0.
2683 if (x < 0.0f)
2684 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2685 else if (x == 0.0f && y <= 0.0f)
2686 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2687 else
2688 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302689 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002690 break;
2691 }
Arun Patolebf790422015-05-18 17:53:04 +05302692
Olli Etuaho51182ab2017-01-22 00:12:29 +00002693 case EOpMod:
2694 {
2695 ASSERT(basicType == EbtFloat);
2696 resultArray = new TConstantUnion[maxObjectSize];
2697 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302698 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002699 float x = unionArrays[0][i].getFConst();
2700 float y = unionArrays[1][i].getFConst();
2701 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302702 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002703 break;
2704 }
Arun Patolebf790422015-05-18 17:53:04 +05302705
Olli Etuaho51182ab2017-01-22 00:12:29 +00002706 case EOpMin:
2707 {
2708 resultArray = new TConstantUnion[maxObjectSize];
2709 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302710 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002711 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302712 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002713 case EbtFloat:
2714 resultArray[i].setFConst(
2715 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2716 break;
2717 case EbtInt:
2718 resultArray[i].setIConst(
2719 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2720 break;
2721 case EbtUInt:
2722 resultArray[i].setUConst(
2723 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2724 break;
2725 default:
2726 UNREACHABLE();
2727 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302728 }
2729 }
2730 break;
Arun Patole274f0702015-05-05 13:33:30 +05302731 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002732
2733 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302734 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002735 resultArray = new TConstantUnion[maxObjectSize];
2736 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302737 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002738 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302739 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002740 case EbtFloat:
2741 resultArray[i].setFConst(
2742 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2743 break;
2744 case EbtInt:
2745 resultArray[i].setIConst(
2746 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2747 break;
2748 case EbtUInt:
2749 resultArray[i].setUConst(
2750 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2751 break;
2752 default:
2753 UNREACHABLE();
2754 break;
Arun Patole274f0702015-05-05 13:33:30 +05302755 }
2756 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002757 break;
Arun Patole274f0702015-05-05 13:33:30 +05302758 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002759
2760 case EOpStep:
2761 {
2762 ASSERT(basicType == EbtFloat);
2763 resultArray = new TConstantUnion[maxObjectSize];
2764 for (size_t i = 0; i < maxObjectSize; i++)
2765 resultArray[i].setFConst(
2766 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2767 break;
2768 }
2769
2770 case EOpLessThanComponentWise:
2771 {
2772 resultArray = new TConstantUnion[maxObjectSize];
2773 for (size_t i = 0; i < maxObjectSize; i++)
2774 {
2775 switch (basicType)
2776 {
2777 case EbtFloat:
2778 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2779 unionArrays[1][i].getFConst());
2780 break;
2781 case EbtInt:
2782 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2783 unionArrays[1][i].getIConst());
2784 break;
2785 case EbtUInt:
2786 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2787 unionArrays[1][i].getUConst());
2788 break;
2789 default:
2790 UNREACHABLE();
2791 break;
2792 }
2793 }
2794 break;
2795 }
2796
2797 case EOpLessThanEqualComponentWise:
2798 {
2799 resultArray = new TConstantUnion[maxObjectSize];
2800 for (size_t i = 0; i < maxObjectSize; i++)
2801 {
2802 switch (basicType)
2803 {
2804 case EbtFloat:
2805 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2806 unionArrays[1][i].getFConst());
2807 break;
2808 case EbtInt:
2809 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2810 unionArrays[1][i].getIConst());
2811 break;
2812 case EbtUInt:
2813 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2814 unionArrays[1][i].getUConst());
2815 break;
2816 default:
2817 UNREACHABLE();
2818 break;
2819 }
2820 }
2821 break;
2822 }
2823
2824 case EOpGreaterThanComponentWise:
2825 {
2826 resultArray = new TConstantUnion[maxObjectSize];
2827 for (size_t i = 0; i < maxObjectSize; i++)
2828 {
2829 switch (basicType)
2830 {
2831 case EbtFloat:
2832 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2833 unionArrays[1][i].getFConst());
2834 break;
2835 case EbtInt:
2836 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2837 unionArrays[1][i].getIConst());
2838 break;
2839 case EbtUInt:
2840 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2841 unionArrays[1][i].getUConst());
2842 break;
2843 default:
2844 UNREACHABLE();
2845 break;
2846 }
2847 }
2848 break;
2849 }
2850 case EOpGreaterThanEqualComponentWise:
2851 {
2852 resultArray = new TConstantUnion[maxObjectSize];
2853 for (size_t i = 0; i < maxObjectSize; i++)
2854 {
2855 switch (basicType)
2856 {
2857 case EbtFloat:
2858 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2859 unionArrays[1][i].getFConst());
2860 break;
2861 case EbtInt:
2862 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2863 unionArrays[1][i].getIConst());
2864 break;
2865 case EbtUInt:
2866 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2867 unionArrays[1][i].getUConst());
2868 break;
2869 default:
2870 UNREACHABLE();
2871 break;
2872 }
2873 }
2874 }
2875 break;
2876
2877 case EOpEqualComponentWise:
2878 {
2879 resultArray = new TConstantUnion[maxObjectSize];
2880 for (size_t i = 0; i < maxObjectSize; i++)
2881 {
2882 switch (basicType)
2883 {
2884 case EbtFloat:
2885 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2886 unionArrays[1][i].getFConst());
2887 break;
2888 case EbtInt:
2889 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2890 unionArrays[1][i].getIConst());
2891 break;
2892 case EbtUInt:
2893 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2894 unionArrays[1][i].getUConst());
2895 break;
2896 case EbtBool:
2897 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2898 unionArrays[1][i].getBConst());
2899 break;
2900 default:
2901 UNREACHABLE();
2902 break;
2903 }
2904 }
2905 break;
2906 }
2907
2908 case EOpNotEqualComponentWise:
2909 {
2910 resultArray = new TConstantUnion[maxObjectSize];
2911 for (size_t i = 0; i < maxObjectSize; i++)
2912 {
2913 switch (basicType)
2914 {
2915 case EbtFloat:
2916 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2917 unionArrays[1][i].getFConst());
2918 break;
2919 case EbtInt:
2920 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2921 unionArrays[1][i].getIConst());
2922 break;
2923 case EbtUInt:
2924 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2925 unionArrays[1][i].getUConst());
2926 break;
2927 case EbtBool:
2928 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2929 unionArrays[1][i].getBConst());
2930 break;
2931 default:
2932 UNREACHABLE();
2933 break;
2934 }
2935 }
2936 break;
2937 }
2938
2939 case EOpDistance:
2940 {
2941 ASSERT(basicType == EbtFloat);
2942 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2943 resultArray = new TConstantUnion();
2944 for (size_t i = 0; i < maxObjectSize; i++)
2945 {
2946 float x = unionArrays[0][i].getFConst();
2947 float y = unionArrays[1][i].getFConst();
2948 distanceArray[i].setFConst(x - y);
2949 }
2950 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2951 break;
2952 }
2953
2954 case EOpDot:
2955 ASSERT(basicType == EbtFloat);
2956 resultArray = new TConstantUnion();
2957 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2958 break;
2959
2960 case EOpCross:
2961 {
2962 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2963 resultArray = new TConstantUnion[maxObjectSize];
2964 float x0 = unionArrays[0][0].getFConst();
2965 float x1 = unionArrays[0][1].getFConst();
2966 float x2 = unionArrays[0][2].getFConst();
2967 float y0 = unionArrays[1][0].getFConst();
2968 float y1 = unionArrays[1][1].getFConst();
2969 float y2 = unionArrays[1][2].getFConst();
2970 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2971 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2972 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2973 break;
2974 }
2975
2976 case EOpReflect:
2977 {
2978 ASSERT(basicType == EbtFloat);
2979 // genType reflect (genType I, genType N) :
2980 // For the incident vector I and surface orientation N, returns the reflection
2981 // direction:
2982 // I - 2 * dot(N, I) * N.
2983 resultArray = new TConstantUnion[maxObjectSize];
2984 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2985 for (size_t i = 0; i < maxObjectSize; i++)
2986 {
2987 float result = unionArrays[0][i].getFConst() -
2988 2.0f * dotProduct * unionArrays[1][i].getFConst();
2989 resultArray[i].setFConst(result);
2990 }
2991 break;
2992 }
2993
2994 case EOpMulMatrixComponentWise:
2995 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002996 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
2997 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00002998 // Perform component-wise matrix multiplication.
2999 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003000 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003001 angle::Matrix<float> result =
3002 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3003 SetUnionArrayFromMatrix(result, resultArray);
3004 break;
3005 }
3006
3007 case EOpOuterProduct:
3008 {
3009 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003010 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3011 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003012 resultArray = new TConstantUnion[numRows * numCols];
3013 angle::Matrix<float> result =
3014 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3015 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3016 SetUnionArrayFromMatrix(result, resultArray);
3017 break;
3018 }
3019
3020 case EOpClamp:
3021 {
3022 resultArray = new TConstantUnion[maxObjectSize];
3023 for (size_t i = 0; i < maxObjectSize; i++)
3024 {
3025 switch (basicType)
3026 {
3027 case EbtFloat:
3028 {
3029 float x = unionArrays[0][i].getFConst();
3030 float min = unionArrays[1][i].getFConst();
3031 float max = unionArrays[2][i].getFConst();
3032 // Results are undefined if min > max.
3033 if (min > max)
3034 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3035 &resultArray[i]);
3036 else
3037 resultArray[i].setFConst(gl::clamp(x, min, max));
3038 break;
3039 }
3040
3041 case EbtInt:
3042 {
3043 int x = unionArrays[0][i].getIConst();
3044 int min = unionArrays[1][i].getIConst();
3045 int max = unionArrays[2][i].getIConst();
3046 // Results are undefined if min > max.
3047 if (min > max)
3048 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3049 &resultArray[i]);
3050 else
3051 resultArray[i].setIConst(gl::clamp(x, min, max));
3052 break;
3053 }
3054 case EbtUInt:
3055 {
3056 unsigned int x = unionArrays[0][i].getUConst();
3057 unsigned int min = unionArrays[1][i].getUConst();
3058 unsigned int max = unionArrays[2][i].getUConst();
3059 // Results are undefined if min > max.
3060 if (min > max)
3061 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3062 &resultArray[i]);
3063 else
3064 resultArray[i].setUConst(gl::clamp(x, min, max));
3065 break;
3066 }
3067 default:
3068 UNREACHABLE();
3069 break;
3070 }
3071 }
3072 break;
3073 }
3074
3075 case EOpMix:
3076 {
3077 ASSERT(basicType == EbtFloat);
3078 resultArray = new TConstantUnion[maxObjectSize];
3079 for (size_t i = 0; i < maxObjectSize; i++)
3080 {
3081 float x = unionArrays[0][i].getFConst();
3082 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003083 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003084 if (type == EbtFloat)
3085 {
3086 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3087 float a = unionArrays[2][i].getFConst();
3088 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3089 }
3090 else // 3rd parameter is EbtBool
3091 {
3092 ASSERT(type == EbtBool);
3093 // Selects which vector each returned component comes from.
3094 // For a component of a that is false, the corresponding component of x is
3095 // returned.
3096 // For a component of a that is true, the corresponding component of y is
3097 // returned.
3098 bool a = unionArrays[2][i].getBConst();
3099 resultArray[i].setFConst(a ? y : x);
3100 }
3101 }
3102 break;
3103 }
3104
3105 case EOpSmoothStep:
3106 {
3107 ASSERT(basicType == EbtFloat);
3108 resultArray = new TConstantUnion[maxObjectSize];
3109 for (size_t i = 0; i < maxObjectSize; i++)
3110 {
3111 float edge0 = unionArrays[0][i].getFConst();
3112 float edge1 = unionArrays[1][i].getFConst();
3113 float x = unionArrays[2][i].getFConst();
3114 // Results are undefined if edge0 >= edge1.
3115 if (edge0 >= edge1)
3116 {
3117 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3118 }
3119 else
3120 {
3121 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3122 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3123 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3124 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3125 }
3126 }
3127 break;
3128 }
3129
Olli Etuaho74da73f2017-02-01 15:37:48 +00003130 case EOpLdexp:
3131 {
3132 resultArray = new TConstantUnion[maxObjectSize];
3133 for (size_t i = 0; i < maxObjectSize; i++)
3134 {
3135 float x = unionArrays[0][i].getFConst();
3136 int exp = unionArrays[1][i].getIConst();
3137 if (exp > 128)
3138 {
3139 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3140 }
3141 else
3142 {
3143 resultArray[i].setFConst(gl::Ldexp(x, exp));
3144 }
3145 }
3146 break;
3147 }
3148
Jamie Madille72595b2017-06-06 15:12:26 -04003149 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003150 {
3151 ASSERT(basicType == EbtFloat);
3152 // genType faceforward(genType N, genType I, genType Nref) :
3153 // If dot(Nref, I) < 0 return N, otherwise return -N.
3154 resultArray = new TConstantUnion[maxObjectSize];
3155 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3156 for (size_t i = 0; i < maxObjectSize; i++)
3157 {
3158 if (dotProduct < 0)
3159 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3160 else
3161 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3162 }
3163 break;
3164 }
3165
3166 case EOpRefract:
3167 {
3168 ASSERT(basicType == EbtFloat);
3169 // genType refract(genType I, genType N, float eta) :
3170 // For the incident vector I and surface normal N, and the ratio of indices of
3171 // refraction eta,
3172 // return the refraction vector. The result is computed by
3173 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3174 // if (k < 0.0)
3175 // return genType(0.0)
3176 // else
3177 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3178 resultArray = new TConstantUnion[maxObjectSize];
3179 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3180 for (size_t i = 0; i < maxObjectSize; i++)
3181 {
3182 float eta = unionArrays[2][i].getFConst();
3183 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3184 if (k < 0.0f)
3185 resultArray[i].setFConst(0.0f);
3186 else
3187 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3188 (eta * dotProduct + sqrtf(k)) *
3189 unionArrays[1][i].getFConst());
3190 }
3191 break;
3192 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003193 case EOpBitfieldExtract:
3194 {
3195 resultArray = new TConstantUnion[maxObjectSize];
3196 for (size_t i = 0; i < maxObjectSize; ++i)
3197 {
3198 int offset = unionArrays[1][0].getIConst();
3199 int bits = unionArrays[2][0].getIConst();
3200 if (bits == 0)
3201 {
3202 if (aggregate->getBasicType() == EbtInt)
3203 {
3204 resultArray[i].setIConst(0);
3205 }
3206 else
3207 {
3208 ASSERT(aggregate->getBasicType() == EbtUInt);
3209 resultArray[i].setUConst(0);
3210 }
3211 }
3212 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3213 {
3214 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3215 &resultArray[i]);
3216 }
3217 else
3218 {
3219 // bits can be 32 here, so we need to avoid bit shift overflow.
3220 uint32_t maskMsb = 1u << (bits - 1);
3221 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3222 if (aggregate->getBasicType() == EbtInt)
3223 {
3224 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3225 uint32_t resultUnsigned = (value & mask) >> offset;
3226 if ((resultUnsigned & maskMsb) != 0)
3227 {
3228 // The most significant bits (from bits+1 to the most significant bit)
3229 // should be set to 1.
3230 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3231 resultUnsigned |= higherBitsMask;
3232 }
3233 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3234 }
3235 else
3236 {
3237 ASSERT(aggregate->getBasicType() == EbtUInt);
3238 uint32_t value = unionArrays[0][i].getUConst();
3239 resultArray[i].setUConst((value & mask) >> offset);
3240 }
3241 }
3242 }
3243 break;
3244 }
3245 case EOpBitfieldInsert:
3246 {
3247 resultArray = new TConstantUnion[maxObjectSize];
3248 for (size_t i = 0; i < maxObjectSize; ++i)
3249 {
3250 int offset = unionArrays[2][0].getIConst();
3251 int bits = unionArrays[3][0].getIConst();
3252 if (bits == 0)
3253 {
3254 if (aggregate->getBasicType() == EbtInt)
3255 {
3256 int32_t base = unionArrays[0][i].getIConst();
3257 resultArray[i].setIConst(base);
3258 }
3259 else
3260 {
3261 ASSERT(aggregate->getBasicType() == EbtUInt);
3262 uint32_t base = unionArrays[0][i].getUConst();
3263 resultArray[i].setUConst(base);
3264 }
3265 }
3266 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3267 {
3268 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3269 &resultArray[i]);
3270 }
3271 else
3272 {
3273 // bits can be 32 here, so we need to avoid bit shift overflow.
3274 uint32_t maskMsb = 1u << (bits - 1);
3275 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3276 uint32_t baseMask = ~insertMask;
3277 if (aggregate->getBasicType() == EbtInt)
3278 {
3279 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3280 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3281 uint32_t resultUnsigned =
3282 (base & baseMask) | ((insert << offset) & insertMask);
3283 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3284 }
3285 else
3286 {
3287 ASSERT(aggregate->getBasicType() == EbtUInt);
3288 uint32_t base = unionArrays[0][i].getUConst();
3289 uint32_t insert = unionArrays[1][i].getUConst();
3290 resultArray[i].setUConst((base & baseMask) |
3291 ((insert << offset) & insertMask));
3292 }
3293 }
3294 }
3295 break;
3296 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003297
3298 default:
3299 UNREACHABLE();
3300 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303301 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003302 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303303}
3304
Jamie Madill45bcc782016-11-07 13:58:48 -05003305} // namespace sh