blob: aac5c2584b4194f974a394e82c6a3754617c3a8d [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() ||
505 declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType()));
506 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
Corentin Wallez509e4562016-08-25 14:55:44 -0400561// static
562TIntermTyped *TIntermTyped::CreateIndexNode(int index)
563{
564 TConstantUnion *u = new TConstantUnion[1];
565 u[0].setIConst(index);
566
567 TType type(EbtInt, EbpUndefined, EvqConst, 1);
568 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
569 return node;
570}
571
572// static
573TIntermTyped *TIntermTyped::CreateZero(const TType &type)
574{
575 TType constType(type);
576 constType.setQualifier(EvqConst);
577
578 if (!type.isArray() && type.getBasicType() != EbtStruct)
579 {
Corentin Wallez509e4562016-08-25 14:55:44 -0400580 size_t size = constType.getObjectSize();
581 TConstantUnion *u = new TConstantUnion[size];
582 for (size_t i = 0; i < size; ++i)
583 {
584 switch (type.getBasicType())
585 {
586 case EbtFloat:
587 u[i].setFConst(0.0f);
588 break;
589 case EbtInt:
590 u[i].setIConst(0);
591 break;
592 case EbtUInt:
593 u[i].setUConst(0u);
594 break;
595 case EbtBool:
596 u[i].setBConst(false);
597 break;
598 default:
Corentin Wallez17a5c062017-01-22 15:20:53 -0500599 // CreateZero is called by ParseContext that keeps parsing even when an error
600 // occurs, so it is possible for CreateZero to be called with non-basic types.
601 // This happens only on error condition but CreateZero needs to return a value
602 // with the correct type to continue the typecheck. That's why we handle
603 // non-basic type by setting whatever value, we just need the type to be right.
604 u[i].setIConst(42);
605 break;
Corentin Wallez509e4562016-08-25 14:55:44 -0400606 }
607 }
608
609 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
610 return node;
611 }
612
Olli Etuaho193c0952017-05-02 15:51:47 +0300613 if (type.getBasicType() == EbtVoid)
614 {
615 // Void array. This happens only on error condition, similarly to the case above. We don't
616 // have a constructor operator for void, so this needs special handling. We'll end up with a
617 // value without the array type, but that should not be a problem.
618 constType.clearArrayness();
619 return CreateZero(constType);
620 }
621
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800622 TIntermSequence *arguments = new TIntermSequence();
Corentin Wallez509e4562016-08-25 14:55:44 -0400623
624 if (type.isArray())
625 {
626 TType elementType(type);
627 elementType.clearArrayness();
628
629 size_t arraySize = type.getArraySize();
630 for (size_t i = 0; i < arraySize; ++i)
631 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800632 arguments->push_back(CreateZero(elementType));
Corentin Wallez509e4562016-08-25 14:55:44 -0400633 }
634 }
635 else
636 {
637 ASSERT(type.getBasicType() == EbtStruct);
638
639 TStructure *structure = type.getStruct();
640 for (const auto &field : structure->fields())
641 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800642 arguments->push_back(CreateZero(*field->type()));
Corentin Wallez509e4562016-08-25 14:55:44 -0400643 }
644 }
645
Olli Etuahoa7ecec32017-05-08 17:43:55 +0300646 return TIntermAggregate::CreateConstructor(constType, arguments);
Corentin Wallez509e4562016-08-25 14:55:44 -0400647}
648
Corentin Wallez36fd1002016-12-08 11:30:44 -0500649// static
650TIntermTyped *TIntermTyped::CreateBool(bool value)
651{
652 TConstantUnion *u = new TConstantUnion[1];
653 u[0].setBConst(value);
654
655 TType type(EbtBool, EbpUndefined, EvqConst, 1);
656 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
657 return node;
658}
659
Olli Etuahod7a25242015-08-18 13:49:45 +0300660TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
661{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200662 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300663}
664
Olli Etuahobd674552016-10-06 13:28:42 +0100665void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
666{
Olli Etuahoec9232b2017-03-27 17:01:37 +0300667 setName(function.getName());
Olli Etuahofe486322017-03-21 09:30:54 +0000668 setId(TSymbolUniqueId(function));
669}
670
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300671TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id)
672 : mId(new TSymbolUniqueId(id)), mKnownToNotHaveSideEffects(false)
Olli Etuahofe486322017-03-21 09:30:54 +0000673{
674}
675
676TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300677 : mName(info.mName), mId(nullptr), mKnownToNotHaveSideEffects(info.mKnownToNotHaveSideEffects)
Olli Etuahofe486322017-03-21 09:30:54 +0000678{
679 if (info.mId)
680 {
681 mId = new TSymbolUniqueId(*info.mId);
682 }
683}
684
685TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
686{
687 mName = info.mName;
688 if (info.mId)
689 {
690 mId = new TSymbolUniqueId(*info.mId);
691 }
692 else
693 {
694 mId = nullptr;
695 }
696 return *this;
697}
698
699void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
700{
701 mId = new TSymbolUniqueId(id);
702}
703
704const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
705{
706 ASSERT(mId);
707 return *mId;
Olli Etuahobd674552016-10-06 13:28:42 +0100708}
709
Olli Etuahod7a25242015-08-18 13:49:45 +0300710TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
711 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300712 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100713 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
714 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300715{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800716 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300717 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800718 TIntermTyped *typedArg = arg->getAsTyped();
719 ASSERT(typedArg != nullptr);
720 TIntermTyped *argCopy = typedArg->deepCopy();
721 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300722 }
723}
724
Olli Etuahofe486322017-03-21 09:30:54 +0000725TIntermAggregate *TIntermAggregate::shallowCopy() const
726{
727 TIntermSequence *copySeq = new TIntermSequence();
728 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
729 TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq);
730 *copyNode->getFunctionSymbolInfo() = mFunctionInfo;
731 copyNode->setLine(mLine);
732 return copyNode;
733}
734
Olli Etuahob6fa0432016-09-28 16:28:05 +0100735TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
736{
737 TIntermTyped *operandCopy = node.mOperand->deepCopy();
738 ASSERT(operandCopy != nullptr);
739 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000740 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100741}
742
Olli Etuahod7a25242015-08-18 13:49:45 +0300743TIntermBinary::TIntermBinary(const TIntermBinary &node)
744 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
745{
746 TIntermTyped *leftCopy = node.mLeft->deepCopy();
747 TIntermTyped *rightCopy = node.mRight->deepCopy();
748 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
749 mLeft = leftCopy;
750 mRight = rightCopy;
751}
752
753TIntermUnary::TIntermUnary(const TIntermUnary &node)
754 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
755{
756 TIntermTyped *operandCopy = node.mOperand->deepCopy();
757 ASSERT(operandCopy != nullptr);
758 mOperand = operandCopy;
759}
760
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300761TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300762{
Olli Etuahod7a25242015-08-18 13:49:45 +0300763 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300764 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
765 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300766 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300767 mCondition = conditionCopy;
768 mTrueExpression = trueCopy;
769 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300770}
771
Jamie Madillb1a85f42014-08-19 15:23:24 -0400772bool TIntermOperator::isAssignment() const
773{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300774 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400775}
776
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300777bool TIntermOperator::isMultiplication() const
778{
779 switch (mOp)
780 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500781 case EOpMul:
782 case EOpMatrixTimesMatrix:
783 case EOpMatrixTimesVector:
784 case EOpMatrixTimesScalar:
785 case EOpVectorTimesMatrix:
786 case EOpVectorTimesScalar:
787 return true;
788 default:
789 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300790 }
791}
792
Jamie Madillb1a85f42014-08-19 15:23:24 -0400793bool TIntermOperator::isConstructor() const
794{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300795 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400796}
797
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800798bool TIntermOperator::isFunctionCall() const
799{
800 switch (mOp)
801 {
802 case EOpCallFunctionInAST:
803 case EOpCallBuiltInFunction:
804 case EOpCallInternalRawFunction:
805 return true;
806 default:
807 return false;
808 }
809}
810
Olli Etuaho1dded802016-08-18 18:13:13 +0300811TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
812{
813 if (left.isMatrix())
814 {
815 if (right.isMatrix())
816 {
817 return EOpMatrixTimesMatrix;
818 }
819 else
820 {
821 if (right.isVector())
822 {
823 return EOpMatrixTimesVector;
824 }
825 else
826 {
827 return EOpMatrixTimesScalar;
828 }
829 }
830 }
831 else
832 {
833 if (right.isMatrix())
834 {
835 if (left.isVector())
836 {
837 return EOpVectorTimesMatrix;
838 }
839 else
840 {
841 return EOpMatrixTimesScalar;
842 }
843 }
844 else
845 {
846 // Neither operand is a matrix.
847 if (left.isVector() == right.isVector())
848 {
849 // Leave as component product.
850 return EOpMul;
851 }
852 else
853 {
854 return EOpVectorTimesScalar;
855 }
856 }
857 }
858}
859
860TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
861{
862 if (left.isMatrix())
863 {
864 if (right.isMatrix())
865 {
866 return EOpMatrixTimesMatrixAssign;
867 }
868 else
869 {
870 // right should be scalar, but this may not be validated yet.
871 return EOpMatrixTimesScalarAssign;
872 }
873 }
874 else
875 {
876 if (right.isMatrix())
877 {
878 // Left should be a vector, but this may not be validated yet.
879 return EOpVectorTimesMatrixAssign;
880 }
881 else
882 {
883 // Neither operand is a matrix.
884 if (left.isVector() == right.isVector())
885 {
886 // Leave as component product.
887 return EOpMulAssign;
888 }
889 else
890 {
891 // left should be vector and right should be scalar, but this may not be validated
892 // yet.
893 return EOpVectorTimesScalarAssign;
894 }
895 }
896 }
897}
898
Jamie Madillb1a85f42014-08-19 15:23:24 -0400899//
900// Make sure the type of a unary operator is appropriate for its
901// combination of operation and operand type.
902//
Olli Etuahoa2234302016-08-31 12:05:39 +0300903void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400904{
Olli Etuahoa2234302016-08-31 12:05:39 +0300905 TQualifier resultQualifier = EvqTemporary;
906 if (mOperand->getQualifier() == EvqConst)
907 resultQualifier = EvqConst;
908
909 unsigned char operandPrimarySize =
910 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400911 switch (mOp)
912 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300913 case EOpFloatBitsToInt:
914 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
915 break;
916 case EOpFloatBitsToUint:
917 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
918 break;
919 case EOpIntBitsToFloat:
920 case EOpUintBitsToFloat:
921 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
922 break;
923 case EOpPackSnorm2x16:
924 case EOpPackUnorm2x16:
925 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800926 case EOpPackUnorm4x8:
927 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300928 setType(TType(EbtUInt, EbpHigh, resultQualifier));
929 break;
930 case EOpUnpackSnorm2x16:
931 case EOpUnpackUnorm2x16:
932 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
933 break;
934 case EOpUnpackHalf2x16:
935 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
936 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800937 case EOpUnpackUnorm4x8:
938 case EOpUnpackSnorm4x8:
939 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
940 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300941 case EOpAny:
942 case EOpAll:
943 setType(TType(EbtBool, EbpUndefined, resultQualifier));
944 break;
945 case EOpLength:
946 case EOpDeterminant:
947 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
948 break;
949 case EOpTranspose:
950 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
951 static_cast<unsigned char>(mOperand->getType().getRows()),
952 static_cast<unsigned char>(mOperand->getType().getCols())));
953 break;
954 case EOpIsInf:
955 case EOpIsNan:
956 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
957 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000958 case EOpBitfieldReverse:
959 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
960 break;
961 case EOpBitCount:
962 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
963 break;
964 case EOpFindLSB:
965 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
966 break;
967 case EOpFindMSB:
968 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
969 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300970 default:
971 setType(mOperand->getType());
972 mType.setQualifier(resultQualifier);
973 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400974 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300975}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400976
Olli Etuahob6fa0432016-09-28 16:28:05 +0100977TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
978 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
979 mOperand(operand),
980 mSwizzleOffsets(swizzleOffsets)
981{
982 ASSERT(mSwizzleOffsets.size() <= 4);
983 promote();
984}
985
Olli Etuahoa2234302016-08-31 12:05:39 +0300986TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
987 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
988{
989 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400990}
991
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300992TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
993 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
994{
995 promote();
996}
997
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000998TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
999 : TIntermNode(), mSymbol(symbol)
1000{
1001 ASSERT(symbol);
1002 setLine(line);
1003}
1004
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001005TIntermTernary::TIntermTernary(TIntermTyped *cond,
1006 TIntermTyped *trueExpression,
1007 TIntermTyped *falseExpression)
1008 : TIntermTyped(trueExpression->getType()),
1009 mCondition(cond),
1010 mTrueExpression(trueExpression),
1011 mFalseExpression(falseExpression)
1012{
1013 getTypePointer()->setQualifier(
1014 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1015}
1016
Olli Etuaho81629262017-04-19 11:56:01 +03001017TIntermLoop::TIntermLoop(TLoopType type,
1018 TIntermNode *init,
1019 TIntermTyped *cond,
1020 TIntermTyped *expr,
1021 TIntermBlock *body)
1022 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1023{
1024 // Declaration nodes with no children can appear if all the declarators just added constants to
1025 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1026 if (mInit && mInit->getAsDeclarationNode() &&
1027 mInit->getAsDeclarationNode()->getSequence()->empty())
1028 {
1029 mInit = nullptr;
1030 }
1031}
1032
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001033// static
1034TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1035 TIntermTyped *trueExpression,
1036 TIntermTyped *falseExpression)
1037{
1038 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1039 falseExpression->getQualifier() == EvqConst)
1040 {
1041 return EvqConst;
1042 }
1043 return EvqTemporary;
1044}
1045
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001046TIntermTyped *TIntermTernary::fold()
1047{
1048 if (mCondition->getAsConstantUnion())
1049 {
1050 if (mCondition->getAsConstantUnion()->getBConst(0))
1051 {
1052 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
1053 return mTrueExpression;
1054 }
1055 else
1056 {
1057 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
1058 return mFalseExpression;
1059 }
1060 }
1061 return this;
1062}
1063
Olli Etuahob6fa0432016-09-28 16:28:05 +01001064void TIntermSwizzle::promote()
1065{
1066 TQualifier resultQualifier = EvqTemporary;
1067 if (mOperand->getQualifier() == EvqConst)
1068 resultQualifier = EvqConst;
1069
1070 auto numFields = mSwizzleOffsets.size();
1071 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1072 static_cast<unsigned char>(numFields)));
1073}
1074
1075bool TIntermSwizzle::hasDuplicateOffsets() const
1076{
1077 int offsetCount[4] = {0u, 0u, 0u, 0u};
1078 for (const auto offset : mSwizzleOffsets)
1079 {
1080 offsetCount[offset]++;
1081 if (offsetCount[offset] > 1)
1082 {
1083 return true;
1084 }
1085 }
1086 return false;
1087}
1088
Olli Etuaho09b04a22016-12-15 13:30:26 +00001089bool TIntermSwizzle::offsetsMatch(int offset) const
1090{
1091 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1092}
1093
Olli Etuahob6fa0432016-09-28 16:28:05 +01001094void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1095{
1096 for (const int offset : mSwizzleOffsets)
1097 {
1098 switch (offset)
1099 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001100 case 0:
1101 *out << "x";
1102 break;
1103 case 1:
1104 *out << "y";
1105 break;
1106 case 2:
1107 *out << "z";
1108 break;
1109 case 3:
1110 *out << "w";
1111 break;
1112 default:
1113 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001114 }
1115 }
1116}
1117
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001118TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1119 const TIntermTyped *left,
1120 const TIntermTyped *right)
1121{
1122 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1123 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1124 right->getQualifier() != EvqConst)
1125 {
1126 return EvqTemporary;
1127 }
1128 return EvqConst;
1129}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001130
1131// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001132void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001133{
Olli Etuaho1dded802016-08-18 18:13:13 +03001134 ASSERT(!isMultiplication() ||
1135 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1136
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001137 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1138 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001139 if (mOp == EOpComma)
1140 {
1141 setType(mRight->getType());
1142 return;
1143 }
1144
Jamie Madillb1a85f42014-08-19 15:23:24 -04001145 // Base assumption: just make the type the same as the left
1146 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001147 setType(mLeft->getType());
1148
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001149 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001150 // Binary operations results in temporary variables unless both
1151 // operands are const.
1152 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1153 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001154 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001155 getTypePointer()->setQualifier(EvqTemporary);
1156 }
1157
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001158 // Handle indexing ops.
1159 switch (mOp)
1160 {
1161 case EOpIndexDirect:
1162 case EOpIndexIndirect:
1163 if (mLeft->isArray())
1164 {
1165 mType.clearArrayness();
1166 }
1167 else if (mLeft->isMatrix())
1168 {
1169 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1170 static_cast<unsigned char>(mLeft->getRows())));
1171 }
1172 else if (mLeft->isVector())
1173 {
1174 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1175 }
1176 else
1177 {
1178 UNREACHABLE();
1179 }
1180 return;
1181 case EOpIndexDirectStruct:
1182 {
1183 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1184 const int i = mRight->getAsConstantUnion()->getIConst(0);
1185 setType(*fields[i]->type());
1186 getTypePointer()->setQualifier(resultQualifier);
1187 return;
1188 }
1189 case EOpIndexDirectInterfaceBlock:
1190 {
1191 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1192 const int i = mRight->getAsConstantUnion()->getIConst(0);
1193 setType(*fields[i]->type());
1194 getTypePointer()->setQualifier(resultQualifier);
1195 return;
1196 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001197 default:
1198 break;
1199 }
1200
1201 ASSERT(mLeft->isArray() == mRight->isArray());
1202
1203 // The result gets promoted to the highest precision.
1204 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1205 getTypePointer()->setPrecision(higherPrecision);
1206
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001207 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001208
1209 //
1210 // All scalars or structs. Code after this test assumes this case is removed!
1211 //
1212 if (nominalSize == 1)
1213 {
1214 switch (mOp)
1215 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001216 //
1217 // Promote to conditional
1218 //
1219 case EOpEqual:
1220 case EOpNotEqual:
1221 case EOpLessThan:
1222 case EOpGreaterThan:
1223 case EOpLessThanEqual:
1224 case EOpGreaterThanEqual:
1225 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1226 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001227
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001228 //
1229 // And and Or operate on conditionals
1230 //
1231 case EOpLogicalAnd:
1232 case EOpLogicalXor:
1233 case EOpLogicalOr:
1234 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1235 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1236 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001237
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001238 default:
1239 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001240 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001241 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001242 }
1243
1244 // If we reach here, at least one of the operands is vector or matrix.
1245 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001246 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001247
Jamie Madillb1a85f42014-08-19 15:23:24 -04001248 switch (mOp)
1249 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001250 case EOpMul:
1251 break;
1252 case EOpMatrixTimesScalar:
1253 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001254 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001255 setType(TType(basicType, higherPrecision, resultQualifier,
1256 static_cast<unsigned char>(mRight->getCols()),
1257 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001258 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001259 break;
1260 case EOpMatrixTimesVector:
1261 setType(TType(basicType, higherPrecision, resultQualifier,
1262 static_cast<unsigned char>(mLeft->getRows()), 1));
1263 break;
1264 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001265 setType(TType(basicType, higherPrecision, resultQualifier,
1266 static_cast<unsigned char>(mRight->getCols()),
1267 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001268 break;
1269 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001270 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001271 static_cast<unsigned char>(nominalSize), 1));
1272 break;
1273 case EOpVectorTimesMatrix:
1274 setType(TType(basicType, higherPrecision, resultQualifier,
1275 static_cast<unsigned char>(mRight->getCols()), 1));
1276 break;
1277 case EOpMulAssign:
1278 case EOpVectorTimesScalarAssign:
1279 case EOpVectorTimesMatrixAssign:
1280 case EOpMatrixTimesScalarAssign:
1281 case EOpMatrixTimesMatrixAssign:
1282 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1283 break;
1284 case EOpAssign:
1285 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001286 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1287 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1288 break;
1289 case EOpAdd:
1290 case EOpSub:
1291 case EOpDiv:
1292 case EOpIMod:
1293 case EOpBitShiftLeft:
1294 case EOpBitShiftRight:
1295 case EOpBitwiseAnd:
1296 case EOpBitwiseXor:
1297 case EOpBitwiseOr:
1298 case EOpAddAssign:
1299 case EOpSubAssign:
1300 case EOpDivAssign:
1301 case EOpIModAssign:
1302 case EOpBitShiftLeftAssign:
1303 case EOpBitShiftRightAssign:
1304 case EOpBitwiseAndAssign:
1305 case EOpBitwiseXorAssign:
1306 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001307 {
1308 const int secondarySize =
1309 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1310 setType(TType(basicType, higherPrecision, resultQualifier,
1311 static_cast<unsigned char>(nominalSize),
1312 static_cast<unsigned char>(secondarySize)));
1313 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001314 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001315 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001316 case EOpEqual:
1317 case EOpNotEqual:
1318 case EOpLessThan:
1319 case EOpGreaterThan:
1320 case EOpLessThanEqual:
1321 case EOpGreaterThanEqual:
1322 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1323 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001324 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001325 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001326
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001327 case EOpIndexDirect:
1328 case EOpIndexIndirect:
1329 case EOpIndexDirectInterfaceBlock:
1330 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001331 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001332 UNREACHABLE();
1333 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001334 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001335 UNREACHABLE();
1336 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001337 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001338}
1339
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001340const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001341{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001342 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001343 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001344 ASSERT(index < static_cast<int>(getType().getArraySize()));
1345 TType arrayElementType = getType();
1346 arrayElementType.clearArrayness();
1347 size_t arrayElementSize = arrayElementType.getObjectSize();
1348 return &mUnionArrayPointer[arrayElementSize * index];
1349 }
1350 else if (isMatrix())
1351 {
1352 ASSERT(index < getType().getCols());
1353 int size = getType().getRows();
1354 return &mUnionArrayPointer[size * index];
1355 }
1356 else if (isVector())
1357 {
1358 ASSERT(index < getType().getNominalSize());
1359 return &mUnionArrayPointer[index];
1360 }
1361 else
1362 {
1363 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001364 return nullptr;
1365 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001366}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001367
Olli Etuahob6fa0432016-09-28 16:28:05 +01001368TIntermTyped *TIntermSwizzle::fold()
1369{
1370 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1371 if (operandConstant == nullptr)
1372 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001373 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001374 }
1375
1376 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1377 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1378 {
1379 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1380 }
1381 return CreateFoldedNode(constArray, this, mType.getQualifier());
1382}
1383
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001384TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1385{
1386 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1387 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1388 switch (mOp)
1389 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001390 case EOpComma:
1391 {
1392 if (mLeft->hasSideEffects())
1393 {
1394 return this;
1395 }
1396 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1397 return mRight;
1398 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001399 case EOpIndexDirect:
1400 {
1401 if (leftConstant == nullptr || rightConstant == nullptr)
1402 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001403 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001404 }
1405 int index = rightConstant->getIConst(0);
1406
1407 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001408 if (!constArray)
1409 {
1410 return this;
1411 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001412 return CreateFoldedNode(constArray, this, mType.getQualifier());
1413 }
1414 case EOpIndexDirectStruct:
1415 {
1416 if (leftConstant == nullptr || rightConstant == nullptr)
1417 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001418 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001419 }
1420 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1421 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1422
1423 size_t previousFieldsSize = 0;
1424 for (size_t i = 0; i < index; ++i)
1425 {
1426 previousFieldsSize += fields[i]->type()->getObjectSize();
1427 }
1428
1429 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1430 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1431 }
1432 case EOpIndexIndirect:
1433 case EOpIndexDirectInterfaceBlock:
1434 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001435 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001436 default:
1437 {
1438 if (leftConstant == nullptr || rightConstant == nullptr)
1439 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001440 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001441 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001442 TConstantUnion *constArray =
1443 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001444 if (!constArray)
1445 {
1446 return this;
1447 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001448
1449 // Nodes may be constant folded without being qualified as constant.
1450 return CreateFoldedNode(constArray, this, mType.getQualifier());
1451 }
1452 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001453}
1454
Olli Etuahof119a262016-08-19 15:54:22 +03001455TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001456{
1457 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1458 if (operandConstant == nullptr)
1459 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001460 return this;
Olli Etuaho95310b02015-06-02 17:43:38 +03001461 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301462
1463 TConstantUnion *constArray = nullptr;
1464 switch (mOp)
1465 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001466 case EOpAny:
1467 case EOpAll:
1468 case EOpLength:
1469 case EOpTranspose:
1470 case EOpDeterminant:
1471 case EOpInverse:
1472 case EOpPackSnorm2x16:
1473 case EOpUnpackSnorm2x16:
1474 case EOpPackUnorm2x16:
1475 case EOpUnpackUnorm2x16:
1476 case EOpPackHalf2x16:
1477 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001478 case EOpPackUnorm4x8:
1479 case EOpPackSnorm4x8:
1480 case EOpUnpackUnorm4x8:
1481 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001482 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1483 break;
1484 default:
1485 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1486 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301487 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001488 if (constArray == nullptr)
1489 {
1490 return this;
1491 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001492
1493 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001494 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001495}
1496
Olli Etuahof119a262016-08-19 15:54:22 +03001497TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001498{
1499 // Make sure that all params are constant before actual constant folding.
1500 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001501 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001502 if (param->getAsConstantUnion() == nullptr)
1503 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001504 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001505 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001506 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001507 TConstantUnion *constArray = nullptr;
1508 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001509 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001510 else
Olli Etuahof119a262016-08-19 15:54:22 +03001511 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001512
1513 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001514 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001515}
1516
Jamie Madillb1a85f42014-08-19 15:23:24 -04001517//
1518// The fold functions see if an operation on a constant can be done in place,
1519// without generating run-time code.
1520//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001521// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001522//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001523TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1524 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001525 TDiagnostics *diagnostics,
1526 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001527{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001528 const TConstantUnion *leftArray = getUnionArrayPointer();
1529 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001530
Olli Etuahof119a262016-08-19 15:54:22 +03001531 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001532
1533 size_t objectSize = getType().getObjectSize();
1534
1535 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1536 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1537 {
1538 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1539 }
1540 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1541 {
1542 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001543 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001544 objectSize = rightNode->getType().getObjectSize();
1545 }
1546
1547 TConstantUnion *resultArray = nullptr;
1548
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001549 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001550 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001551 case EOpAdd:
1552 resultArray = new TConstantUnion[objectSize];
1553 for (size_t i = 0; i < objectSize; i++)
1554 resultArray[i] =
1555 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1556 break;
1557 case EOpSub:
1558 resultArray = new TConstantUnion[objectSize];
1559 for (size_t i = 0; i < objectSize; i++)
1560 resultArray[i] =
1561 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1562 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001563
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001564 case EOpMul:
1565 case EOpVectorTimesScalar:
1566 case EOpMatrixTimesScalar:
1567 resultArray = new TConstantUnion[objectSize];
1568 for (size_t i = 0; i < objectSize; i++)
1569 resultArray[i] =
1570 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1571 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001572
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001573 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001574 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001575 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001576 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001577
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001578 const int leftCols = getCols();
1579 const int leftRows = getRows();
1580 const int rightCols = rightNode->getType().getCols();
1581 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001582 const int resultCols = rightCols;
1583 const int resultRows = leftRows;
1584
1585 resultArray = new TConstantUnion[resultCols * resultRows];
1586 for (int row = 0; row < resultRows; row++)
1587 {
1588 for (int column = 0; column < resultCols; column++)
1589 {
1590 resultArray[resultRows * column + row].setFConst(0.0f);
1591 for (int i = 0; i < leftCols; i++)
1592 {
1593 resultArray[resultRows * column + row].setFConst(
1594 resultArray[resultRows * column + row].getFConst() +
1595 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001596 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001597 }
1598 }
1599 }
1600 }
1601 break;
1602
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001603 case EOpDiv:
1604 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001605 {
1606 resultArray = new TConstantUnion[objectSize];
1607 for (size_t i = 0; i < objectSize; i++)
1608 {
1609 switch (getType().getBasicType())
1610 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001611 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001612 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001613 ASSERT(op == EOpDiv);
1614 float dividend = leftArray[i].getFConst();
1615 float divisor = rightArray[i].getFConst();
1616 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001617 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001619 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001620 diagnostics->warning(
1621 getLine(),
1622 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001623 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001624 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001625 }
1626 else
1627 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001628 diagnostics->warning(getLine(),
1629 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001630 bool negativeResult =
1631 std::signbit(dividend) != std::signbit(divisor);
1632 resultArray[i].setFConst(
1633 negativeResult ? -std::numeric_limits<float>::infinity()
1634 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001635 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001636 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001637 else if (gl::isInf(dividend) && gl::isInf(divisor))
1638 {
1639 diagnostics->warning(getLine(),
1640 "Infinity divided by infinity during constant "
1641 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001642 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001643 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1644 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001645 else
1646 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001647 float result = dividend / divisor;
1648 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001649 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001650 diagnostics->warning(
1651 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001652 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001653 }
1654 resultArray[i].setFConst(result);
1655 }
1656 break;
1657 }
1658 case EbtInt:
1659 if (rightArray[i] == 0)
1660 {
1661 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001662 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001663 resultArray[i].setIConst(INT_MAX);
1664 }
1665 else
1666 {
1667 int lhs = leftArray[i].getIConst();
1668 int divisor = rightArray[i].getIConst();
1669 if (op == EOpDiv)
1670 {
1671 // Check for the special case where the minimum representable number
1672 // is
1673 // divided by -1. If left alone this leads to integer overflow in
1674 // C++.
1675 // ESSL 3.00.6 section 4.1.3 Integers:
1676 // "However, for the case where the minimum representable value is
1677 // divided by -1, it is allowed to return either the minimum
1678 // representable value or the maximum representable value."
1679 if (lhs == -0x7fffffff - 1 && divisor == -1)
1680 {
1681 resultArray[i].setIConst(0x7fffffff);
1682 }
1683 else
1684 {
1685 resultArray[i].setIConst(lhs / divisor);
1686 }
Olli Etuahod4453572016-09-27 13:21:46 +01001687 }
1688 else
1689 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001690 ASSERT(op == EOpIMod);
1691 if (lhs < 0 || divisor < 0)
1692 {
1693 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1694 // when
1695 // either one of the operands is negative.
1696 diagnostics->warning(getLine(),
1697 "Negative modulus operator operand "
1698 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001699 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001700 resultArray[i].setIConst(0);
1701 }
1702 else
1703 {
1704 resultArray[i].setIConst(lhs % divisor);
1705 }
Olli Etuahod4453572016-09-27 13:21:46 +01001706 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001707 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001708 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001709
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001710 case EbtUInt:
1711 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001712 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001713 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001714 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001715 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001716 }
1717 else
1718 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001719 if (op == EOpDiv)
1720 {
1721 resultArray[i].setUConst(leftArray[i].getUConst() /
1722 rightArray[i].getUConst());
1723 }
1724 else
1725 {
1726 ASSERT(op == EOpIMod);
1727 resultArray[i].setUConst(leftArray[i].getUConst() %
1728 rightArray[i].getUConst());
1729 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001730 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001731 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001732
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001733 default:
1734 UNREACHABLE();
1735 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001736 }
1737 }
1738 }
1739 break;
1740
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001741 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001742 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001743 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001744 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001745
1746 const int matrixCols = getCols();
1747 const int matrixRows = getRows();
1748
1749 resultArray = new TConstantUnion[matrixRows];
1750
1751 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1752 {
1753 resultArray[matrixRow].setFConst(0.0f);
1754 for (int col = 0; col < matrixCols; col++)
1755 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001756 resultArray[matrixRow].setFConst(
1757 resultArray[matrixRow].getFConst() +
1758 leftArray[col * matrixRows + matrixRow].getFConst() *
1759 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001760 }
1761 }
1762 }
1763 break;
1764
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001765 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001766 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001767 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001768 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001769
1770 const int matrixCols = rightNode->getType().getCols();
1771 const int matrixRows = rightNode->getType().getRows();
1772
1773 resultArray = new TConstantUnion[matrixCols];
1774
1775 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1776 {
1777 resultArray[matrixCol].setFConst(0.0f);
1778 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1779 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001780 resultArray[matrixCol].setFConst(
1781 resultArray[matrixCol].getFConst() +
1782 leftArray[matrixRow].getFConst() *
1783 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001784 }
1785 }
1786 }
1787 break;
1788
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001789 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001790 {
1791 resultArray = new TConstantUnion[objectSize];
1792 for (size_t i = 0; i < objectSize; i++)
1793 {
1794 resultArray[i] = leftArray[i] && rightArray[i];
1795 }
1796 }
1797 break;
1798
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001799 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001800 {
1801 resultArray = new TConstantUnion[objectSize];
1802 for (size_t i = 0; i < objectSize; i++)
1803 {
1804 resultArray[i] = leftArray[i] || rightArray[i];
1805 }
1806 }
1807 break;
1808
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001809 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001810 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001811 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001812 resultArray = new TConstantUnion[objectSize];
1813 for (size_t i = 0; i < objectSize; i++)
1814 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001815 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001816 }
1817 }
1818 break;
1819
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001820 case EOpBitwiseAnd:
1821 resultArray = new TConstantUnion[objectSize];
1822 for (size_t i = 0; i < objectSize; i++)
1823 resultArray[i] = leftArray[i] & rightArray[i];
1824 break;
1825 case EOpBitwiseXor:
1826 resultArray = new TConstantUnion[objectSize];
1827 for (size_t i = 0; i < objectSize; i++)
1828 resultArray[i] = leftArray[i] ^ rightArray[i];
1829 break;
1830 case EOpBitwiseOr:
1831 resultArray = new TConstantUnion[objectSize];
1832 for (size_t i = 0; i < objectSize; i++)
1833 resultArray[i] = leftArray[i] | rightArray[i];
1834 break;
1835 case EOpBitShiftLeft:
1836 resultArray = new TConstantUnion[objectSize];
1837 for (size_t i = 0; i < objectSize; i++)
1838 resultArray[i] =
1839 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1840 break;
1841 case EOpBitShiftRight:
1842 resultArray = new TConstantUnion[objectSize];
1843 for (size_t i = 0; i < objectSize; i++)
1844 resultArray[i] =
1845 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1846 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001847
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001848 case EOpLessThan:
1849 ASSERT(objectSize == 1);
1850 resultArray = new TConstantUnion[1];
1851 resultArray->setBConst(*leftArray < *rightArray);
1852 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001853
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001854 case EOpGreaterThan:
1855 ASSERT(objectSize == 1);
1856 resultArray = new TConstantUnion[1];
1857 resultArray->setBConst(*leftArray > *rightArray);
1858 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001859
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001860 case EOpLessThanEqual:
1861 ASSERT(objectSize == 1);
1862 resultArray = new TConstantUnion[1];
1863 resultArray->setBConst(!(*leftArray > *rightArray));
1864 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001865
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001866 case EOpGreaterThanEqual:
1867 ASSERT(objectSize == 1);
1868 resultArray = new TConstantUnion[1];
1869 resultArray->setBConst(!(*leftArray < *rightArray));
1870 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001871
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001872 case EOpEqual:
1873 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001874 {
1875 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001876 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001877 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001878 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001879 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001880 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001881 equal = false;
1882 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001883 }
1884 }
1885 if (op == EOpEqual)
1886 {
1887 resultArray->setBConst(equal);
1888 }
1889 else
1890 {
1891 resultArray->setBConst(!equal);
1892 }
1893 }
1894 break;
1895
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001896 default:
1897 UNREACHABLE();
1898 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001899 }
1900 return resultArray;
1901}
1902
Olli Etuahof119a262016-08-19 15:54:22 +03001903// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1904// code. Returns the constant value to keep using. Nullptr should not be returned.
1905TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001906{
Olli Etuahof119a262016-08-19 15:54:22 +03001907 // Do operations where the return type may have a different number of components compared to the
1908 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001909
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001910 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001911 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301912
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001913 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301914 TConstantUnion *resultArray = nullptr;
1915 switch (op)
1916 {
Olli Etuahof119a262016-08-19 15:54:22 +03001917 case EOpAny:
1918 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301919 resultArray = new TConstantUnion();
1920 resultArray->setBConst(false);
1921 for (size_t i = 0; i < objectSize; i++)
1922 {
1923 if (operandArray[i].getBConst())
1924 {
1925 resultArray->setBConst(true);
1926 break;
1927 }
1928 }
1929 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301930
Olli Etuahof119a262016-08-19 15:54:22 +03001931 case EOpAll:
1932 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301933 resultArray = new TConstantUnion();
1934 resultArray->setBConst(true);
1935 for (size_t i = 0; i < objectSize; i++)
1936 {
1937 if (!operandArray[i].getBConst())
1938 {
1939 resultArray->setBConst(false);
1940 break;
1941 }
1942 }
1943 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301944
Olli Etuahof119a262016-08-19 15:54:22 +03001945 case EOpLength:
1946 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301947 resultArray = new TConstantUnion();
1948 resultArray->setFConst(VectorLength(operandArray, objectSize));
1949 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301950
Olli Etuahof119a262016-08-19 15:54:22 +03001951 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301952 {
Olli Etuahof119a262016-08-19 15:54:22 +03001953 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301954 resultArray = new TConstantUnion[objectSize];
1955 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001956 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301957 SetUnionArrayFromMatrix(result, resultArray);
1958 break;
1959 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301960
Olli Etuahof119a262016-08-19 15:54:22 +03001961 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301962 {
Olli Etuahof119a262016-08-19 15:54:22 +03001963 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301964 unsigned int size = getType().getNominalSize();
1965 ASSERT(size >= 2 && size <= 4);
1966 resultArray = new TConstantUnion();
1967 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1968 break;
1969 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301970
Olli Etuahof119a262016-08-19 15:54:22 +03001971 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301972 {
Olli Etuahof119a262016-08-19 15:54:22 +03001973 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301974 unsigned int size = getType().getNominalSize();
1975 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001976 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301977 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1978 SetUnionArrayFromMatrix(result, resultArray);
1979 break;
1980 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301981
Olli Etuahof119a262016-08-19 15:54:22 +03001982 case EOpPackSnorm2x16:
1983 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301984 ASSERT(getType().getNominalSize() == 2);
1985 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001986 resultArray->setUConst(
1987 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301988 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301989
Olli Etuahof119a262016-08-19 15:54:22 +03001990 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301991 {
Olli Etuahof119a262016-08-19 15:54:22 +03001992 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301993 resultArray = new TConstantUnion[2];
1994 float f1, f2;
1995 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1996 resultArray[0].setFConst(f1);
1997 resultArray[1].setFConst(f2);
1998 break;
1999 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302000
Olli Etuahof119a262016-08-19 15:54:22 +03002001 case EOpPackUnorm2x16:
2002 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302003 ASSERT(getType().getNominalSize() == 2);
2004 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002005 resultArray->setUConst(
2006 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302007 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302008
Olli Etuahof119a262016-08-19 15:54:22 +03002009 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302010 {
Olli Etuahof119a262016-08-19 15:54:22 +03002011 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302012 resultArray = new TConstantUnion[2];
2013 float f1, f2;
2014 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2015 resultArray[0].setFConst(f1);
2016 resultArray[1].setFConst(f2);
2017 break;
2018 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302019
Olli Etuahof119a262016-08-19 15:54:22 +03002020 case EOpPackHalf2x16:
2021 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302022 ASSERT(getType().getNominalSize() == 2);
2023 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002024 resultArray->setUConst(
2025 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302026 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302027
Olli Etuahof119a262016-08-19 15:54:22 +03002028 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302029 {
Olli Etuahof119a262016-08-19 15:54:22 +03002030 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302031 resultArray = new TConstantUnion[2];
2032 float f1, f2;
2033 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2034 resultArray[0].setFConst(f1);
2035 resultArray[1].setFConst(f2);
2036 break;
2037 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302038
Olli Etuaho25aef452017-01-29 16:15:44 -08002039 case EOpPackUnorm4x8:
2040 {
2041 ASSERT(getType().getBasicType() == EbtFloat);
2042 resultArray = new TConstantUnion();
2043 resultArray->setUConst(
2044 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2045 operandArray[2].getFConst(), operandArray[3].getFConst()));
2046 break;
2047 }
2048 case EOpPackSnorm4x8:
2049 {
2050 ASSERT(getType().getBasicType() == EbtFloat);
2051 resultArray = new TConstantUnion();
2052 resultArray->setUConst(
2053 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2054 operandArray[2].getFConst(), operandArray[3].getFConst()));
2055 break;
2056 }
2057 case EOpUnpackUnorm4x8:
2058 {
2059 ASSERT(getType().getBasicType() == EbtUInt);
2060 resultArray = new TConstantUnion[4];
2061 float f[4];
2062 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2063 for (size_t i = 0; i < 4; ++i)
2064 {
2065 resultArray[i].setFConst(f[i]);
2066 }
2067 break;
2068 }
2069 case EOpUnpackSnorm4x8:
2070 {
2071 ASSERT(getType().getBasicType() == EbtUInt);
2072 resultArray = new TConstantUnion[4];
2073 float f[4];
2074 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2075 for (size_t i = 0; i < 4; ++i)
2076 {
2077 resultArray[i].setFConst(f[i]);
2078 }
2079 break;
2080 }
2081
Olli Etuahof119a262016-08-19 15:54:22 +03002082 default:
2083 UNREACHABLE();
2084 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302085 }
2086
2087 return resultArray;
2088}
2089
Olli Etuahof119a262016-08-19 15:54:22 +03002090TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2091 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302092{
Olli Etuahof119a262016-08-19 15:54:22 +03002093 // Do unary operations where each component of the result is computed based on the corresponding
2094 // component of the operand. Also folds normalize, though the divisor in that case takes all
2095 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302096
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002097 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002098 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002099
2100 size_t objectSize = getType().getObjectSize();
2101
Arun Patoleab2b9a22015-07-06 18:27:56 +05302102 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2103 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302104 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002105 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302106 {
Olli Etuahof119a262016-08-19 15:54:22 +03002107 case EOpNegative:
2108 switch (getType().getBasicType())
2109 {
2110 case EbtFloat:
2111 resultArray[i].setFConst(-operandArray[i].getFConst());
2112 break;
2113 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002114 if (operandArray[i] == std::numeric_limits<int>::min())
2115 {
2116 // The minimum representable integer doesn't have a positive
2117 // counterpart, rather the negation overflows and in ESSL is supposed to
2118 // wrap back to the minimum representable integer. Make sure that we
2119 // don't actually let the negation overflow, which has undefined
2120 // behavior in C++.
2121 resultArray[i].setIConst(std::numeric_limits<int>::min());
2122 }
2123 else
2124 {
2125 resultArray[i].setIConst(-operandArray[i].getIConst());
2126 }
Olli Etuahof119a262016-08-19 15:54:22 +03002127 break;
2128 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002129 if (operandArray[i] == 0x80000000u)
2130 {
2131 resultArray[i].setUConst(0x80000000u);
2132 }
2133 else
2134 {
2135 resultArray[i].setUConst(static_cast<unsigned int>(
2136 -static_cast<int>(operandArray[i].getUConst())));
2137 }
Olli Etuahof119a262016-08-19 15:54:22 +03002138 break;
2139 default:
2140 UNREACHABLE();
2141 return nullptr;
2142 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302143 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302144
Olli Etuahof119a262016-08-19 15:54:22 +03002145 case EOpPositive:
2146 switch (getType().getBasicType())
2147 {
2148 case EbtFloat:
2149 resultArray[i].setFConst(operandArray[i].getFConst());
2150 break;
2151 case EbtInt:
2152 resultArray[i].setIConst(operandArray[i].getIConst());
2153 break;
2154 case EbtUInt:
2155 resultArray[i].setUConst(static_cast<unsigned int>(
2156 static_cast<int>(operandArray[i].getUConst())));
2157 break;
2158 default:
2159 UNREACHABLE();
2160 return nullptr;
2161 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302162 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302163
Olli Etuahof119a262016-08-19 15:54:22 +03002164 case EOpLogicalNot:
2165 switch (getType().getBasicType())
2166 {
2167 case EbtBool:
2168 resultArray[i].setBConst(!operandArray[i].getBConst());
2169 break;
2170 default:
2171 UNREACHABLE();
2172 return nullptr;
2173 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302174 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302175
Olli Etuahof119a262016-08-19 15:54:22 +03002176 case EOpBitwiseNot:
2177 switch (getType().getBasicType())
2178 {
2179 case EbtInt:
2180 resultArray[i].setIConst(~operandArray[i].getIConst());
2181 break;
2182 case EbtUInt:
2183 resultArray[i].setUConst(~operandArray[i].getUConst());
2184 break;
2185 default:
2186 UNREACHABLE();
2187 return nullptr;
2188 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302189 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302190
Olli Etuahof119a262016-08-19 15:54:22 +03002191 case EOpRadians:
2192 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302193 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2194 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302195
Olli Etuahof119a262016-08-19 15:54:22 +03002196 case EOpDegrees:
2197 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302198 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2199 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302200
Olli Etuahof119a262016-08-19 15:54:22 +03002201 case EOpSin:
2202 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302203 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302204
Olli Etuahof119a262016-08-19 15:54:22 +03002205 case EOpCos:
2206 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2207 break;
2208
2209 case EOpTan:
2210 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2211 break;
2212
2213 case EOpAsin:
2214 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2215 // 0.
2216 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2217 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2218 diagnostics, &resultArray[i]);
2219 else
2220 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2221 break;
2222
2223 case EOpAcos:
2224 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2225 // 0.
2226 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2227 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2228 diagnostics, &resultArray[i]);
2229 else
2230 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2231 break;
2232
2233 case EOpAtan:
2234 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2235 break;
2236
2237 case EOpSinh:
2238 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2239 break;
2240
2241 case EOpCosh:
2242 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2243 break;
2244
2245 case EOpTanh:
2246 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2247 break;
2248
2249 case EOpAsinh:
2250 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2251 break;
2252
2253 case EOpAcosh:
2254 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2255 if (operandArray[i].getFConst() < 1.0f)
2256 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2257 diagnostics, &resultArray[i]);
2258 else
2259 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2260 break;
2261
2262 case EOpAtanh:
2263 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2264 // 0.
2265 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2266 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2267 diagnostics, &resultArray[i]);
2268 else
2269 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2270 break;
2271
2272 case EOpAbs:
2273 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302274 {
Olli Etuahof119a262016-08-19 15:54:22 +03002275 case EbtFloat:
2276 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2277 break;
2278 case EbtInt:
2279 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2280 break;
2281 default:
2282 UNREACHABLE();
2283 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302284 }
2285 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002286
2287 case EOpSign:
2288 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302289 {
Olli Etuahof119a262016-08-19 15:54:22 +03002290 case EbtFloat:
2291 {
2292 float fConst = operandArray[i].getFConst();
2293 float fResult = 0.0f;
2294 if (fConst > 0.0f)
2295 fResult = 1.0f;
2296 else if (fConst < 0.0f)
2297 fResult = -1.0f;
2298 resultArray[i].setFConst(fResult);
2299 break;
2300 }
2301 case EbtInt:
2302 {
2303 int iConst = operandArray[i].getIConst();
2304 int iResult = 0;
2305 if (iConst > 0)
2306 iResult = 1;
2307 else if (iConst < 0)
2308 iResult = -1;
2309 resultArray[i].setIConst(iResult);
2310 break;
2311 }
2312 default:
2313 UNREACHABLE();
2314 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302315 }
2316 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302317
Olli Etuahof119a262016-08-19 15:54:22 +03002318 case EOpFloor:
2319 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2320 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302321
Olli Etuahof119a262016-08-19 15:54:22 +03002322 case EOpTrunc:
2323 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2324 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302325
Olli Etuahof119a262016-08-19 15:54:22 +03002326 case EOpRound:
2327 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2328 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302329
Olli Etuahof119a262016-08-19 15:54:22 +03002330 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302331 {
Olli Etuahof119a262016-08-19 15:54:22 +03002332 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302333 float x = operandArray[i].getFConst();
2334 float result;
2335 float fractPart = modff(x, &result);
2336 if (fabsf(fractPart) == 0.5f)
2337 result = 2.0f * roundf(x / 2.0f);
2338 else
2339 result = roundf(x);
2340 resultArray[i].setFConst(result);
2341 break;
2342 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302343
Olli Etuahof119a262016-08-19 15:54:22 +03002344 case EOpCeil:
2345 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2346 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302347
Olli Etuahof119a262016-08-19 15:54:22 +03002348 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302349 {
Olli Etuahof119a262016-08-19 15:54:22 +03002350 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302351 float x = operandArray[i].getFConst();
2352 resultArray[i].setFConst(x - floorf(x));
2353 break;
2354 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302355
Olli Etuahof119a262016-08-19 15:54:22 +03002356 case EOpIsNan:
2357 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302358 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2359 break;
Arun Patole551279e2015-07-07 18:18:23 +05302360
Olli Etuahof119a262016-08-19 15:54:22 +03002361 case EOpIsInf:
2362 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302363 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2364 break;
Arun Patole551279e2015-07-07 18:18:23 +05302365
Olli Etuahof119a262016-08-19 15:54:22 +03002366 case EOpFloatBitsToInt:
2367 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302368 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2369 break;
Arun Patole551279e2015-07-07 18:18:23 +05302370
Olli Etuahof119a262016-08-19 15:54:22 +03002371 case EOpFloatBitsToUint:
2372 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302373 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2374 break;
Arun Patole551279e2015-07-07 18:18:23 +05302375
Olli Etuahof119a262016-08-19 15:54:22 +03002376 case EOpIntBitsToFloat:
2377 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302378 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2379 break;
Arun Patole551279e2015-07-07 18:18:23 +05302380
Olli Etuahof119a262016-08-19 15:54:22 +03002381 case EOpUintBitsToFloat:
2382 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302383 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2384 break;
Arun Patole551279e2015-07-07 18:18:23 +05302385
Olli Etuahof119a262016-08-19 15:54:22 +03002386 case EOpExp:
2387 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2388 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302389
Olli Etuahof119a262016-08-19 15:54:22 +03002390 case EOpLog:
2391 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2392 if (operandArray[i].getFConst() <= 0.0f)
2393 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2394 diagnostics, &resultArray[i]);
2395 else
2396 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2397 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302398
Olli Etuahof119a262016-08-19 15:54:22 +03002399 case EOpExp2:
2400 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2401 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302402
Olli Etuahof119a262016-08-19 15:54:22 +03002403 case EOpLog2:
2404 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2405 // And log2f is not available on some plarforms like old android, so just using
2406 // log(x)/log(2) here.
2407 if (operandArray[i].getFConst() <= 0.0f)
2408 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2409 diagnostics, &resultArray[i]);
2410 else
2411 {
2412 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2413 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2414 }
2415 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302416
Olli Etuahof119a262016-08-19 15:54:22 +03002417 case EOpSqrt:
2418 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2419 if (operandArray[i].getFConst() < 0.0f)
2420 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2421 diagnostics, &resultArray[i]);
2422 else
2423 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2424 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302425
Olli Etuahof119a262016-08-19 15:54:22 +03002426 case EOpInverseSqrt:
2427 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2428 // so getting the square root first using builtin function sqrt() and then taking
2429 // its inverse.
2430 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2431 // result to 0.
2432 if (operandArray[i].getFConst() <= 0.0f)
2433 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2434 diagnostics, &resultArray[i]);
2435 else
2436 {
2437 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2438 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2439 }
2440 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302441
Olli Etuahod68924e2017-01-02 17:34:40 +00002442 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002443 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302444 resultArray[i].setBConst(!operandArray[i].getBConst());
2445 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302446
Olli Etuahof119a262016-08-19 15:54:22 +03002447 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302448 {
Olli Etuahof119a262016-08-19 15:54:22 +03002449 ASSERT(getType().getBasicType() == EbtFloat);
2450 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302451 float length = VectorLength(operandArray, objectSize);
2452 if (length)
2453 resultArray[i].setFConst(x / length);
2454 else
Olli Etuahof119a262016-08-19 15:54:22 +03002455 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2456 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302457 break;
2458 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002459 case EOpBitfieldReverse:
2460 {
2461 uint32_t value;
2462 if (getType().getBasicType() == EbtInt)
2463 {
2464 value = static_cast<uint32_t>(operandArray[i].getIConst());
2465 }
2466 else
2467 {
2468 ASSERT(getType().getBasicType() == EbtUInt);
2469 value = operandArray[i].getUConst();
2470 }
2471 uint32_t result = gl::BitfieldReverse(value);
2472 if (getType().getBasicType() == EbtInt)
2473 {
2474 resultArray[i].setIConst(static_cast<int32_t>(result));
2475 }
2476 else
2477 {
2478 resultArray[i].setUConst(result);
2479 }
2480 break;
2481 }
2482 case EOpBitCount:
2483 {
2484 uint32_t value;
2485 if (getType().getBasicType() == EbtInt)
2486 {
2487 value = static_cast<uint32_t>(operandArray[i].getIConst());
2488 }
2489 else
2490 {
2491 ASSERT(getType().getBasicType() == EbtUInt);
2492 value = operandArray[i].getUConst();
2493 }
2494 int result = gl::BitCount(value);
2495 resultArray[i].setIConst(result);
2496 break;
2497 }
2498 case EOpFindLSB:
2499 {
2500 uint32_t value;
2501 if (getType().getBasicType() == EbtInt)
2502 {
2503 value = static_cast<uint32_t>(operandArray[i].getIConst());
2504 }
2505 else
2506 {
2507 ASSERT(getType().getBasicType() == EbtUInt);
2508 value = operandArray[i].getUConst();
2509 }
2510 resultArray[i].setIConst(gl::FindLSB(value));
2511 break;
2512 }
2513 case EOpFindMSB:
2514 {
2515 uint32_t value;
2516 if (getType().getBasicType() == EbtInt)
2517 {
2518 int intValue = operandArray[i].getIConst();
2519 value = static_cast<uint32_t>(intValue);
2520 if (intValue < 0)
2521 {
2522 // Look for zero instead of one in value. This also handles the intValue ==
2523 // -1 special case, where the return value needs to be -1.
2524 value = ~value;
2525 }
2526 }
2527 else
2528 {
2529 ASSERT(getType().getBasicType() == EbtUInt);
2530 value = operandArray[i].getUConst();
2531 }
2532 resultArray[i].setIConst(gl::FindMSB(value));
2533 break;
2534 }
Olli Etuahof119a262016-08-19 15:54:22 +03002535 case EOpDFdx:
2536 case EOpDFdy:
2537 case EOpFwidth:
2538 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302539 // Derivatives of constant arguments should be 0.
2540 resultArray[i].setFConst(0.0f);
2541 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302542
Olli Etuahof119a262016-08-19 15:54:22 +03002543 default:
2544 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302545 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302546 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002547
Arun Patoleab2b9a22015-07-06 18:27:56 +05302548 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002549}
2550
Olli Etuahof119a262016-08-19 15:54:22 +03002551void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2552 FloatTypeUnaryFunc builtinFunc,
2553 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302554{
2555 ASSERT(builtinFunc);
2556
Olli Etuahof119a262016-08-19 15:54:22 +03002557 ASSERT(getType().getBasicType() == EbtFloat);
2558 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302559}
2560
Jamie Madillb1a85f42014-08-19 15:23:24 -04002561// static
Olli Etuahof119a262016-08-19 15:54:22 +03002562TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002563{
2564 ASSERT(aggregate->getSequence()->size() > 0u);
2565 size_t resultSize = aggregate->getType().getObjectSize();
2566 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2567 TBasicType basicType = aggregate->getBasicType();
2568
2569 size_t resultIndex = 0u;
2570
2571 if (aggregate->getSequence()->size() == 1u)
2572 {
2573 TIntermNode *argument = aggregate->getSequence()->front();
2574 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2575 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2576 // Check the special case of constructing a matrix diagonal from a single scalar,
2577 // or a vector from a single scalar.
2578 if (argumentConstant->getType().getObjectSize() == 1u)
2579 {
2580 if (aggregate->isMatrix())
2581 {
2582 int resultCols = aggregate->getType().getCols();
2583 int resultRows = aggregate->getType().getRows();
2584 for (int col = 0; col < resultCols; ++col)
2585 {
2586 for (int row = 0; row < resultRows; ++row)
2587 {
2588 if (col == row)
2589 {
2590 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2591 }
2592 else
2593 {
2594 resultArray[resultIndex].setFConst(0.0f);
2595 }
2596 ++resultIndex;
2597 }
2598 }
2599 }
2600 else
2601 {
2602 while (resultIndex < resultSize)
2603 {
2604 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2605 ++resultIndex;
2606 }
2607 }
2608 ASSERT(resultIndex == resultSize);
2609 return resultArray;
2610 }
2611 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2612 {
2613 // The special case of constructing a matrix from a matrix.
2614 int argumentCols = argumentConstant->getType().getCols();
2615 int argumentRows = argumentConstant->getType().getRows();
2616 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002617 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002618 for (int col = 0; col < resultCols; ++col)
2619 {
2620 for (int row = 0; row < resultRows; ++row)
2621 {
2622 if (col < argumentCols && row < argumentRows)
2623 {
2624 resultArray[resultIndex].cast(basicType,
2625 argumentUnionArray[col * argumentRows + row]);
2626 }
2627 else if (col == row)
2628 {
2629 resultArray[resultIndex].setFConst(1.0f);
2630 }
2631 else
2632 {
2633 resultArray[resultIndex].setFConst(0.0f);
2634 }
2635 ++resultIndex;
2636 }
2637 }
2638 ASSERT(resultIndex == resultSize);
2639 return resultArray;
2640 }
2641 }
2642
2643 for (TIntermNode *&argument : *aggregate->getSequence())
2644 {
2645 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2646 size_t argumentSize = argumentConstant->getType().getObjectSize();
2647 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2648 for (size_t i = 0u; i < argumentSize; ++i)
2649 {
2650 if (resultIndex >= resultSize)
2651 break;
2652 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2653 ++resultIndex;
2654 }
2655 }
2656 ASSERT(resultIndex == resultSize);
2657 return resultArray;
2658}
2659
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002660bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2661{
2662 switch (op)
2663 {
2664 case EOpAtan:
2665 case EOpPow:
2666 case EOpMod:
2667 case EOpMin:
2668 case EOpMax:
2669 case EOpClamp:
2670 case EOpMix:
2671 case EOpStep:
2672 case EOpSmoothStep:
2673 case EOpLdexp:
2674 case EOpMulMatrixComponentWise:
2675 case EOpOuterProduct:
2676 case EOpEqualComponentWise:
2677 case EOpNotEqualComponentWise:
2678 case EOpLessThanComponentWise:
2679 case EOpLessThanEqualComponentWise:
2680 case EOpGreaterThanComponentWise:
2681 case EOpGreaterThanEqualComponentWise:
2682 case EOpDistance:
2683 case EOpDot:
2684 case EOpCross:
2685 case EOpFaceforward:
2686 case EOpReflect:
2687 case EOpRefract:
2688 case EOpBitfieldExtract:
2689 case EOpBitfieldInsert:
2690 return true;
2691 default:
2692 return false;
2693 }
2694}
2695
Olli Etuaho1d122782015-11-06 15:35:17 +02002696// static
Olli Etuahof119a262016-08-19 15:54:22 +03002697TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2698 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302699{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002700 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002701 TIntermSequence *arguments = aggregate->getSequence();
2702 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2703 std::vector<const TConstantUnion *> unionArrays(argsCount);
2704 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002705 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302706 TBasicType basicType = EbtVoid;
2707 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002708 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302709 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002710 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2711 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302712
2713 if (i == 0)
2714 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002715 basicType = argConstant->getType().getBasicType();
2716 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302717 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002718 unionArrays[i] = argConstant->getUnionArrayPointer();
2719 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002720 if (objectSizes[i] > maxObjectSize)
2721 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302722 }
2723
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002724 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302725 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002726 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302727 if (objectSizes[i] != maxObjectSize)
2728 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2729 }
Arun Patole274f0702015-05-05 13:33:30 +05302730
Olli Etuahob43846e2015-06-02 18:18:57 +03002731 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002732
2733 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302734 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002735 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302736 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002737 ASSERT(basicType == EbtFloat);
2738 resultArray = new TConstantUnion[maxObjectSize];
2739 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302740 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002741 float y = unionArrays[0][i].getFConst();
2742 float x = unionArrays[1][i].getFConst();
2743 // Results are undefined if x and y are both 0.
2744 if (x == 0.0f && y == 0.0f)
2745 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2746 else
2747 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302748 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002749 break;
2750 }
Arun Patolebf790422015-05-18 17:53:04 +05302751
Olli Etuaho51182ab2017-01-22 00:12:29 +00002752 case EOpPow:
2753 {
2754 ASSERT(basicType == EbtFloat);
2755 resultArray = new TConstantUnion[maxObjectSize];
2756 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302757 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002758 float x = unionArrays[0][i].getFConst();
2759 float y = unionArrays[1][i].getFConst();
2760 // Results are undefined if x < 0.
2761 // Results are undefined if x = 0 and y <= 0.
2762 if (x < 0.0f)
2763 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2764 else if (x == 0.0f && y <= 0.0f)
2765 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2766 else
2767 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302768 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002769 break;
2770 }
Arun Patolebf790422015-05-18 17:53:04 +05302771
Olli Etuaho51182ab2017-01-22 00:12:29 +00002772 case EOpMod:
2773 {
2774 ASSERT(basicType == EbtFloat);
2775 resultArray = new TConstantUnion[maxObjectSize];
2776 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302777 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002778 float x = unionArrays[0][i].getFConst();
2779 float y = unionArrays[1][i].getFConst();
2780 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302781 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002782 break;
2783 }
Arun Patolebf790422015-05-18 17:53:04 +05302784
Olli Etuaho51182ab2017-01-22 00:12:29 +00002785 case EOpMin:
2786 {
2787 resultArray = new TConstantUnion[maxObjectSize];
2788 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302789 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002790 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302791 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002792 case EbtFloat:
2793 resultArray[i].setFConst(
2794 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2795 break;
2796 case EbtInt:
2797 resultArray[i].setIConst(
2798 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2799 break;
2800 case EbtUInt:
2801 resultArray[i].setUConst(
2802 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2803 break;
2804 default:
2805 UNREACHABLE();
2806 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302807 }
2808 }
2809 break;
Arun Patole274f0702015-05-05 13:33:30 +05302810 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002811
2812 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302813 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002814 resultArray = new TConstantUnion[maxObjectSize];
2815 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302816 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002817 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302818 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002819 case EbtFloat:
2820 resultArray[i].setFConst(
2821 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2822 break;
2823 case EbtInt:
2824 resultArray[i].setIConst(
2825 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2826 break;
2827 case EbtUInt:
2828 resultArray[i].setUConst(
2829 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2830 break;
2831 default:
2832 UNREACHABLE();
2833 break;
Arun Patole274f0702015-05-05 13:33:30 +05302834 }
2835 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002836 break;
Arun Patole274f0702015-05-05 13:33:30 +05302837 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002838
2839 case EOpStep:
2840 {
2841 ASSERT(basicType == EbtFloat);
2842 resultArray = new TConstantUnion[maxObjectSize];
2843 for (size_t i = 0; i < maxObjectSize; i++)
2844 resultArray[i].setFConst(
2845 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2846 break;
2847 }
2848
2849 case EOpLessThanComponentWise:
2850 {
2851 resultArray = new TConstantUnion[maxObjectSize];
2852 for (size_t i = 0; i < maxObjectSize; i++)
2853 {
2854 switch (basicType)
2855 {
2856 case EbtFloat:
2857 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2858 unionArrays[1][i].getFConst());
2859 break;
2860 case EbtInt:
2861 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2862 unionArrays[1][i].getIConst());
2863 break;
2864 case EbtUInt:
2865 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2866 unionArrays[1][i].getUConst());
2867 break;
2868 default:
2869 UNREACHABLE();
2870 break;
2871 }
2872 }
2873 break;
2874 }
2875
2876 case EOpLessThanEqualComponentWise:
2877 {
2878 resultArray = new TConstantUnion[maxObjectSize];
2879 for (size_t i = 0; i < maxObjectSize; i++)
2880 {
2881 switch (basicType)
2882 {
2883 case EbtFloat:
2884 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2885 unionArrays[1][i].getFConst());
2886 break;
2887 case EbtInt:
2888 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2889 unionArrays[1][i].getIConst());
2890 break;
2891 case EbtUInt:
2892 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2893 unionArrays[1][i].getUConst());
2894 break;
2895 default:
2896 UNREACHABLE();
2897 break;
2898 }
2899 }
2900 break;
2901 }
2902
2903 case EOpGreaterThanComponentWise:
2904 {
2905 resultArray = new TConstantUnion[maxObjectSize];
2906 for (size_t i = 0; i < maxObjectSize; i++)
2907 {
2908 switch (basicType)
2909 {
2910 case EbtFloat:
2911 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2912 unionArrays[1][i].getFConst());
2913 break;
2914 case EbtInt:
2915 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2916 unionArrays[1][i].getIConst());
2917 break;
2918 case EbtUInt:
2919 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2920 unionArrays[1][i].getUConst());
2921 break;
2922 default:
2923 UNREACHABLE();
2924 break;
2925 }
2926 }
2927 break;
2928 }
2929 case EOpGreaterThanEqualComponentWise:
2930 {
2931 resultArray = new TConstantUnion[maxObjectSize];
2932 for (size_t i = 0; i < maxObjectSize; i++)
2933 {
2934 switch (basicType)
2935 {
2936 case EbtFloat:
2937 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2938 unionArrays[1][i].getFConst());
2939 break;
2940 case EbtInt:
2941 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2942 unionArrays[1][i].getIConst());
2943 break;
2944 case EbtUInt:
2945 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2946 unionArrays[1][i].getUConst());
2947 break;
2948 default:
2949 UNREACHABLE();
2950 break;
2951 }
2952 }
2953 }
2954 break;
2955
2956 case EOpEqualComponentWise:
2957 {
2958 resultArray = new TConstantUnion[maxObjectSize];
2959 for (size_t i = 0; i < maxObjectSize; i++)
2960 {
2961 switch (basicType)
2962 {
2963 case EbtFloat:
2964 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2965 unionArrays[1][i].getFConst());
2966 break;
2967 case EbtInt:
2968 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2969 unionArrays[1][i].getIConst());
2970 break;
2971 case EbtUInt:
2972 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2973 unionArrays[1][i].getUConst());
2974 break;
2975 case EbtBool:
2976 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2977 unionArrays[1][i].getBConst());
2978 break;
2979 default:
2980 UNREACHABLE();
2981 break;
2982 }
2983 }
2984 break;
2985 }
2986
2987 case EOpNotEqualComponentWise:
2988 {
2989 resultArray = new TConstantUnion[maxObjectSize];
2990 for (size_t i = 0; i < maxObjectSize; i++)
2991 {
2992 switch (basicType)
2993 {
2994 case EbtFloat:
2995 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2996 unionArrays[1][i].getFConst());
2997 break;
2998 case EbtInt:
2999 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3000 unionArrays[1][i].getIConst());
3001 break;
3002 case EbtUInt:
3003 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3004 unionArrays[1][i].getUConst());
3005 break;
3006 case EbtBool:
3007 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3008 unionArrays[1][i].getBConst());
3009 break;
3010 default:
3011 UNREACHABLE();
3012 break;
3013 }
3014 }
3015 break;
3016 }
3017
3018 case EOpDistance:
3019 {
3020 ASSERT(basicType == EbtFloat);
3021 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3022 resultArray = new TConstantUnion();
3023 for (size_t i = 0; i < maxObjectSize; i++)
3024 {
3025 float x = unionArrays[0][i].getFConst();
3026 float y = unionArrays[1][i].getFConst();
3027 distanceArray[i].setFConst(x - y);
3028 }
3029 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3030 break;
3031 }
3032
3033 case EOpDot:
3034 ASSERT(basicType == EbtFloat);
3035 resultArray = new TConstantUnion();
3036 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3037 break;
3038
3039 case EOpCross:
3040 {
3041 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3042 resultArray = new TConstantUnion[maxObjectSize];
3043 float x0 = unionArrays[0][0].getFConst();
3044 float x1 = unionArrays[0][1].getFConst();
3045 float x2 = unionArrays[0][2].getFConst();
3046 float y0 = unionArrays[1][0].getFConst();
3047 float y1 = unionArrays[1][1].getFConst();
3048 float y2 = unionArrays[1][2].getFConst();
3049 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3050 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3051 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3052 break;
3053 }
3054
3055 case EOpReflect:
3056 {
3057 ASSERT(basicType == EbtFloat);
3058 // genType reflect (genType I, genType N) :
3059 // For the incident vector I and surface orientation N, returns the reflection
3060 // direction:
3061 // I - 2 * dot(N, I) * N.
3062 resultArray = new TConstantUnion[maxObjectSize];
3063 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3064 for (size_t i = 0; i < maxObjectSize; i++)
3065 {
3066 float result = unionArrays[0][i].getFConst() -
3067 2.0f * dotProduct * unionArrays[1][i].getFConst();
3068 resultArray[i].setFConst(result);
3069 }
3070 break;
3071 }
3072
3073 case EOpMulMatrixComponentWise:
3074 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003075 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3076 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003077 // Perform component-wise matrix multiplication.
3078 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003079 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003080 angle::Matrix<float> result =
3081 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3082 SetUnionArrayFromMatrix(result, resultArray);
3083 break;
3084 }
3085
3086 case EOpOuterProduct:
3087 {
3088 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003089 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3090 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003091 resultArray = new TConstantUnion[numRows * numCols];
3092 angle::Matrix<float> result =
3093 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3094 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3095 SetUnionArrayFromMatrix(result, resultArray);
3096 break;
3097 }
3098
3099 case EOpClamp:
3100 {
3101 resultArray = new TConstantUnion[maxObjectSize];
3102 for (size_t i = 0; i < maxObjectSize; i++)
3103 {
3104 switch (basicType)
3105 {
3106 case EbtFloat:
3107 {
3108 float x = unionArrays[0][i].getFConst();
3109 float min = unionArrays[1][i].getFConst();
3110 float max = unionArrays[2][i].getFConst();
3111 // Results are undefined if min > max.
3112 if (min > max)
3113 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3114 &resultArray[i]);
3115 else
3116 resultArray[i].setFConst(gl::clamp(x, min, max));
3117 break;
3118 }
3119
3120 case EbtInt:
3121 {
3122 int x = unionArrays[0][i].getIConst();
3123 int min = unionArrays[1][i].getIConst();
3124 int max = unionArrays[2][i].getIConst();
3125 // Results are undefined if min > max.
3126 if (min > max)
3127 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3128 &resultArray[i]);
3129 else
3130 resultArray[i].setIConst(gl::clamp(x, min, max));
3131 break;
3132 }
3133 case EbtUInt:
3134 {
3135 unsigned int x = unionArrays[0][i].getUConst();
3136 unsigned int min = unionArrays[1][i].getUConst();
3137 unsigned int max = unionArrays[2][i].getUConst();
3138 // Results are undefined if min > max.
3139 if (min > max)
3140 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3141 &resultArray[i]);
3142 else
3143 resultArray[i].setUConst(gl::clamp(x, min, max));
3144 break;
3145 }
3146 default:
3147 UNREACHABLE();
3148 break;
3149 }
3150 }
3151 break;
3152 }
3153
3154 case EOpMix:
3155 {
3156 ASSERT(basicType == EbtFloat);
3157 resultArray = new TConstantUnion[maxObjectSize];
3158 for (size_t i = 0; i < maxObjectSize; i++)
3159 {
3160 float x = unionArrays[0][i].getFConst();
3161 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003162 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003163 if (type == EbtFloat)
3164 {
3165 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3166 float a = unionArrays[2][i].getFConst();
3167 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3168 }
3169 else // 3rd parameter is EbtBool
3170 {
3171 ASSERT(type == EbtBool);
3172 // Selects which vector each returned component comes from.
3173 // For a component of a that is false, the corresponding component of x is
3174 // returned.
3175 // For a component of a that is true, the corresponding component of y is
3176 // returned.
3177 bool a = unionArrays[2][i].getBConst();
3178 resultArray[i].setFConst(a ? y : x);
3179 }
3180 }
3181 break;
3182 }
3183
3184 case EOpSmoothStep:
3185 {
3186 ASSERT(basicType == EbtFloat);
3187 resultArray = new TConstantUnion[maxObjectSize];
3188 for (size_t i = 0; i < maxObjectSize; i++)
3189 {
3190 float edge0 = unionArrays[0][i].getFConst();
3191 float edge1 = unionArrays[1][i].getFConst();
3192 float x = unionArrays[2][i].getFConst();
3193 // Results are undefined if edge0 >= edge1.
3194 if (edge0 >= edge1)
3195 {
3196 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3197 }
3198 else
3199 {
3200 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3201 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3202 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3203 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3204 }
3205 }
3206 break;
3207 }
3208
Olli Etuaho74da73f2017-02-01 15:37:48 +00003209 case EOpLdexp:
3210 {
3211 resultArray = new TConstantUnion[maxObjectSize];
3212 for (size_t i = 0; i < maxObjectSize; i++)
3213 {
3214 float x = unionArrays[0][i].getFConst();
3215 int exp = unionArrays[1][i].getIConst();
3216 if (exp > 128)
3217 {
3218 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3219 }
3220 else
3221 {
3222 resultArray[i].setFConst(gl::Ldexp(x, exp));
3223 }
3224 }
3225 break;
3226 }
3227
Jamie Madille72595b2017-06-06 15:12:26 -04003228 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003229 {
3230 ASSERT(basicType == EbtFloat);
3231 // genType faceforward(genType N, genType I, genType Nref) :
3232 // If dot(Nref, I) < 0 return N, otherwise return -N.
3233 resultArray = new TConstantUnion[maxObjectSize];
3234 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3235 for (size_t i = 0; i < maxObjectSize; i++)
3236 {
3237 if (dotProduct < 0)
3238 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3239 else
3240 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3241 }
3242 break;
3243 }
3244
3245 case EOpRefract:
3246 {
3247 ASSERT(basicType == EbtFloat);
3248 // genType refract(genType I, genType N, float eta) :
3249 // For the incident vector I and surface normal N, and the ratio of indices of
3250 // refraction eta,
3251 // return the refraction vector. The result is computed by
3252 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3253 // if (k < 0.0)
3254 // return genType(0.0)
3255 // else
3256 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3257 resultArray = new TConstantUnion[maxObjectSize];
3258 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3259 for (size_t i = 0; i < maxObjectSize; i++)
3260 {
3261 float eta = unionArrays[2][i].getFConst();
3262 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3263 if (k < 0.0f)
3264 resultArray[i].setFConst(0.0f);
3265 else
3266 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3267 (eta * dotProduct + sqrtf(k)) *
3268 unionArrays[1][i].getFConst());
3269 }
3270 break;
3271 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003272 case EOpBitfieldExtract:
3273 {
3274 resultArray = new TConstantUnion[maxObjectSize];
3275 for (size_t i = 0; i < maxObjectSize; ++i)
3276 {
3277 int offset = unionArrays[1][0].getIConst();
3278 int bits = unionArrays[2][0].getIConst();
3279 if (bits == 0)
3280 {
3281 if (aggregate->getBasicType() == EbtInt)
3282 {
3283 resultArray[i].setIConst(0);
3284 }
3285 else
3286 {
3287 ASSERT(aggregate->getBasicType() == EbtUInt);
3288 resultArray[i].setUConst(0);
3289 }
3290 }
3291 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3292 {
3293 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3294 &resultArray[i]);
3295 }
3296 else
3297 {
3298 // bits can be 32 here, so we need to avoid bit shift overflow.
3299 uint32_t maskMsb = 1u << (bits - 1);
3300 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3301 if (aggregate->getBasicType() == EbtInt)
3302 {
3303 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3304 uint32_t resultUnsigned = (value & mask) >> offset;
3305 if ((resultUnsigned & maskMsb) != 0)
3306 {
3307 // The most significant bits (from bits+1 to the most significant bit)
3308 // should be set to 1.
3309 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3310 resultUnsigned |= higherBitsMask;
3311 }
3312 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3313 }
3314 else
3315 {
3316 ASSERT(aggregate->getBasicType() == EbtUInt);
3317 uint32_t value = unionArrays[0][i].getUConst();
3318 resultArray[i].setUConst((value & mask) >> offset);
3319 }
3320 }
3321 }
3322 break;
3323 }
3324 case EOpBitfieldInsert:
3325 {
3326 resultArray = new TConstantUnion[maxObjectSize];
3327 for (size_t i = 0; i < maxObjectSize; ++i)
3328 {
3329 int offset = unionArrays[2][0].getIConst();
3330 int bits = unionArrays[3][0].getIConst();
3331 if (bits == 0)
3332 {
3333 if (aggregate->getBasicType() == EbtInt)
3334 {
3335 int32_t base = unionArrays[0][i].getIConst();
3336 resultArray[i].setIConst(base);
3337 }
3338 else
3339 {
3340 ASSERT(aggregate->getBasicType() == EbtUInt);
3341 uint32_t base = unionArrays[0][i].getUConst();
3342 resultArray[i].setUConst(base);
3343 }
3344 }
3345 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3346 {
3347 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3348 &resultArray[i]);
3349 }
3350 else
3351 {
3352 // bits can be 32 here, so we need to avoid bit shift overflow.
3353 uint32_t maskMsb = 1u << (bits - 1);
3354 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3355 uint32_t baseMask = ~insertMask;
3356 if (aggregate->getBasicType() == EbtInt)
3357 {
3358 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3359 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3360 uint32_t resultUnsigned =
3361 (base & baseMask) | ((insert << offset) & insertMask);
3362 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3363 }
3364 else
3365 {
3366 ASSERT(aggregate->getBasicType() == EbtUInt);
3367 uint32_t base = unionArrays[0][i].getUConst();
3368 uint32_t insert = unionArrays[1][i].getUConst();
3369 resultArray[i].setUConst((base & baseMask) |
3370 ((insert << offset) & insertMask));
3371 }
3372 }
3373 }
3374 break;
3375 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003376
3377 default:
3378 UNREACHABLE();
3379 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303380 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003381 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303382}
3383
Jamie Madill45bcc782016-11-07 13:58:48 -05003384} // namespace sh