blob: 335da38d14021dc3654d8897283b9832236bd451 [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
Olli Etuahoae4dbf32017-12-08 20:49:00 +0100147TName::TName(const TString *name) : mName(name ? (*name) : ""), mIsInternal(false)
148{
149}
150
Jamie Madillb1a85f42014-08-19 15:23:24 -0400151////////////////////////////////////////////////////////////////
152//
153// Member functions of the nodes used for building the tree.
154//
155////////////////////////////////////////////////////////////////
156
Olli Etuahod2a67b92014-10-21 16:42:57 +0300157void TIntermTyped::setTypePreservePrecision(const TType &t)
158{
159 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500160 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300161 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
162 mType.setPrecision(precision);
163}
164
Jamie Madillb1a85f42014-08-19 15:23:24 -0400165#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500166 if (node == original) \
167 { \
168 node = static_cast<type *>(replacement); \
169 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400170 }
171
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500172bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400173{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300174 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400175 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
176 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
177 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100178 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400179 return false;
180}
181
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500182bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400183{
184 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
185 return false;
186}
187
Olli Etuahob6fa0432016-09-28 16:28:05 +0100188bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
189{
190 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
191 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
192 return false;
193}
194
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500195bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400196{
197 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
198 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
199 return false;
200}
201
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500202bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400203{
Olli Etuahoa2234302016-08-31 12:05:39 +0300204 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400205 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
206 return false;
207}
208
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000209bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
210{
211 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
212 return false;
213}
214
Olli Etuaho336b1472016-10-05 16:37:55 +0100215bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
216{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000217 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100218 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
219 return false;
220}
221
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500222bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400223{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100224 return replaceChildNodeInternal(original, replacement);
225}
226
227bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
228{
229 return replaceChildNodeInternal(original, replacement);
230}
231
Olli Etuaho16c745a2017-01-16 17:02:27 +0000232bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
233{
234 return replaceChildNodeInternal(original, replacement);
235}
236
Olli Etuaho13389b62016-10-16 11:48:18 +0100237bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
238{
239 return replaceChildNodeInternal(original, replacement);
240}
241
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100242bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
243{
244 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400245 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100246 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400247 }
248 return false;
249}
250
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100251bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
252 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300253{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100254 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300255 {
256 if (*it == original)
257 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100258 it = getSequence()->erase(it);
259 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300260 return true;
261 }
262 }
263 return false;
264}
265
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100266bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
267 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300268{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100269 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300270 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300271 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300272 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100273 auto it = getSequence()->begin() + position;
274 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300275 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300276}
277
Olli Etuaho195be942017-12-04 23:40:14 +0200278TIntermSymbol::TIntermSymbol(const TVariable *variable)
279 : TIntermTyped(variable->getType()), mId(variable->uniqueId()), mSymbol(variable->name())
280{
281 if (variable->symbolType() == SymbolType::AngleInternal)
282 {
283 mSymbol.setInternal(true);
284 }
285}
286
Olli Etuahofe486322017-03-21 09:30:54 +0000287TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
288 TIntermSequence *arguments)
289{
Olli Etuaho0c371002017-12-13 17:00:25 +0400290 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000291}
292
Olli Etuaho0c371002017-12-13 17:00:25 +0400293TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
294 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000295{
Olli Etuaho0c371002017-12-13 17:00:25 +0400296 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000297}
298
299TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
300 TIntermSequence *arguments)
301{
302 TIntermAggregate *callNode =
Olli Etuaho0c371002017-12-13 17:00:25 +0400303 new TIntermAggregate(&func, func.getReturnType(), EOpCallBuiltInFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000304 // Note that name needs to be set before texture function type is determined.
305 callNode->setBuiltInFunctionPrecision();
306 return callNode;
307}
308
309TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000310 TIntermSequence *arguments)
311{
Olli Etuaho0c371002017-12-13 17:00:25 +0400312 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000313}
314
315TIntermAggregate *TIntermAggregate::Create(const TType &type,
316 TOperator op,
317 TIntermSequence *arguments)
318{
Olli Etuahofe486322017-03-21 09:30:54 +0000319 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400320 ASSERT(op != EOpCallInternalRawFunction); // Should use CreateRawFunctionCall
Olli Etuahofe486322017-03-21 09:30:54 +0000321 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400322 ASSERT(op != EOpConstruct); // Should use CreateConstructor
323 return new TIntermAggregate(nullptr, type, op, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000324}
325
Olli Etuaho0c371002017-12-13 17:00:25 +0400326TIntermAggregate::TIntermAggregate(const TFunction *func,
327 const TType &type,
328 TOperator op,
329 TIntermSequence *arguments)
330 : TIntermOperator(op),
331 mUseEmulatedFunction(false),
332 mGotPrecisionFromChildren(false),
333 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800334{
335 if (arguments != nullptr)
336 {
337 mArguments.swap(*arguments);
338 }
Olli Etuaho0c371002017-12-13 17:00:25 +0400339 if (mFunction)
340 {
341 mFunctionInfo.setFromFunction(*mFunction);
342 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800343 setTypePrecisionAndQualifier(type);
344}
345
346void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
347{
348 setType(type);
349 mType.setQualifier(EvqTemporary);
350 if (!isFunctionCall())
351 {
352 if (isConstructor())
353 {
354 // Structs should not be precision qualified, the individual members may be.
355 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300356 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800357 {
358 setPrecisionFromChildren();
359 }
360 }
361 else
362 {
363 setPrecisionForBuiltInOp();
364 }
365 if (areChildrenConstQualified())
366 {
367 mType.setQualifier(EvqConst);
368 }
369 }
370}
371
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200372bool TIntermAggregate::areChildrenConstQualified()
373{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800374 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200375 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800376 TIntermTyped *typedArg = arg->getAsTyped();
377 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200378 {
379 return false;
380 }
381 }
382 return true;
383}
384
Olli Etuahod2a67b92014-10-21 16:42:57 +0300385void TIntermAggregate::setPrecisionFromChildren()
386{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300387 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300388 if (getBasicType() == EbtBool)
389 {
390 mType.setPrecision(EbpUndefined);
391 return;
392 }
393
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500394 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800395 TIntermSequence::iterator childIter = mArguments.begin();
396 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300397 {
398 TIntermTyped *typed = (*childIter)->getAsTyped();
399 if (typed)
400 precision = GetHigherPrecision(typed->getPrecision(), precision);
401 ++childIter;
402 }
403 mType.setPrecision(precision);
404}
405
Olli Etuaho9250cb22017-01-21 10:51:27 +0000406void TIntermAggregate::setPrecisionForBuiltInOp()
407{
408 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800409 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000410 if (!setPrecisionForSpecialBuiltInOp())
411 {
412 setPrecisionFromChildren();
413 }
414}
415
416bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
417{
418 switch (mOp)
419 {
420 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800421 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
422 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000423 return true;
424 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800425 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
426 mArguments[1]->getAsTyped()->getPrecision()));
427 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000428 return true;
429 case EOpUaddCarry:
430 case EOpUsubBorrow:
431 mType.setPrecision(EbpHigh);
432 return true;
433 default:
434 return false;
435 }
436}
437
Olli Etuahod2a67b92014-10-21 16:42:57 +0300438void TIntermAggregate::setBuiltInFunctionPrecision()
439{
440 // All built-ins returning bool should be handled as ops, not functions.
441 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800442 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300443
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800444 TPrecision precision = EbpUndefined;
445 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300446 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800447 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300448 // ESSL spec section 8: texture functions get their precision from the sampler.
449 if (typed && IsSampler(typed->getBasicType()))
450 {
451 precision = typed->getPrecision();
452 break;
453 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300454 }
455 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
456 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100457 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300458 mType.setPrecision(EbpHigh);
459 else
460 mType.setPrecision(precision);
461}
462
Olli Etuahof2209f72017-04-01 12:45:55 +0300463TString TIntermAggregate::getSymbolTableMangledName() const
464{
465 ASSERT(!isConstructor());
466 switch (mOp)
467 {
468 case EOpCallInternalRawFunction:
469 case EOpCallBuiltInFunction:
470 case EOpCallFunctionInAST:
471 return TFunction::GetMangledNameFromCall(mFunctionInfo.getName(), mArguments);
472 default:
473 TString opString = GetOperatorString(mOp);
474 return TFunction::GetMangledNameFromCall(opString, mArguments);
475 }
476}
477
Olli Etuaho0c371002017-12-13 17:00:25 +0400478const char *TIntermAggregate::functionName() const
479{
480 ASSERT(!isConstructor());
481 switch (mOp)
482 {
483 case EOpCallInternalRawFunction:
484 case EOpCallBuiltInFunction:
485 case EOpCallFunctionInAST:
486 return mFunction->name()->c_str();
487 default:
488 return GetOperatorString(mOp);
489 }
490}
491
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300492bool TIntermAggregate::hasSideEffects() const
493{
Olli Etuaho0c371002017-12-13 17:00:25 +0400494 if (isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300495 {
496 for (TIntermNode *arg : mArguments)
497 {
498 if (arg->getAsTyped()->hasSideEffects())
499 {
500 return true;
501 }
502 }
503 return false;
504 }
505 // Conservatively assume most aggregate operators have side-effects
506 return true;
507}
508
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100509void TIntermBlock::appendStatement(TIntermNode *statement)
510{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300511 // Declaration nodes with no children can appear if it was an empty declaration or if all the
512 // declarators just added constants to the symbol table instead of generating code. We still
513 // need to add the declaration to the AST in that case because it might be relevant to the
514 // validity of switch/case.
515 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100516 {
517 mStatements.push_back(statement);
518 }
519}
520
Olli Etuaho16c745a2017-01-16 17:02:27 +0000521void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
522{
523 ASSERT(parameter != nullptr);
524 mParameters.push_back(parameter);
525}
526
Olli Etuaho13389b62016-10-16 11:48:18 +0100527void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
528{
529 ASSERT(declarator != nullptr);
530 ASSERT(declarator->getAsSymbolNode() != nullptr ||
531 (declarator->getAsBinaryNode() != nullptr &&
532 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
533 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300534 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100535 mDeclarators.push_back(declarator);
536}
537
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300538bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
539{
540 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
541 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
542 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
543 return false;
544}
545
Olli Etuaho57961272016-09-14 13:57:46 +0300546bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400547{
548 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100549 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
550 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400551 return false;
552}
553
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500554bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200555{
556 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100557 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300558 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200559 return false;
560}
561
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500562bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200563{
564 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
565 return false;
566}
567
Olli Etuahod7a25242015-08-18 13:49:45 +0300568TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
569{
570 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
571 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
572 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
573 mLine = node.mLine;
574}
575
Olli Etuahod4f4c112016-04-15 15:11:24 +0300576bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
577{
578 TIntermAggregate *constructor = getAsAggregate();
579 if (!constructor || !constructor->isConstructor())
580 {
581 return false;
582 }
583 for (TIntermNode *&node : *constructor->getSequence())
584 {
585 if (!node->getAsConstantUnion())
586 return false;
587 }
588 return true;
589}
590
Olli Etuahod7a25242015-08-18 13:49:45 +0300591TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
592{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200593 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300594}
595
Olli Etuahobd674552016-10-06 13:28:42 +0100596void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
597{
Olli Etuaho0c371002017-12-13 17:00:25 +0400598 mName.setString(*function.name());
599 mName.setInternal(function.symbolType() == SymbolType::AngleInternal);
Olli Etuahofe486322017-03-21 09:30:54 +0000600 setId(TSymbolUniqueId(function));
601}
602
Olli Etuaho0c371002017-12-13 17:00:25 +0400603TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id) : mId(new TSymbolUniqueId(id))
Olli Etuahofe486322017-03-21 09:30:54 +0000604{
605}
606
607TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
Olli Etuaho0c371002017-12-13 17:00:25 +0400608 : mName(info.mName), mId(nullptr)
Olli Etuahofe486322017-03-21 09:30:54 +0000609{
610 if (info.mId)
611 {
612 mId = new TSymbolUniqueId(*info.mId);
613 }
614}
615
616TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
617{
618 mName = info.mName;
619 if (info.mId)
620 {
621 mId = new TSymbolUniqueId(*info.mId);
622 }
623 else
624 {
625 mId = nullptr;
626 }
627 return *this;
628}
629
630void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
631{
632 mId = new TSymbolUniqueId(id);
633}
634
635const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
636{
637 ASSERT(mId);
638 return *mId;
Olli Etuahobd674552016-10-06 13:28:42 +0100639}
640
Olli Etuahod7a25242015-08-18 13:49:45 +0300641TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
642 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300643 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100644 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400645 mFunctionInfo(node.mFunctionInfo),
646 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300647{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800648 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300649 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800650 TIntermTyped *typedArg = arg->getAsTyped();
651 ASSERT(typedArg != nullptr);
652 TIntermTyped *argCopy = typedArg->deepCopy();
653 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300654 }
655}
656
Olli Etuahofe486322017-03-21 09:30:54 +0000657TIntermAggregate *TIntermAggregate::shallowCopy() const
658{
659 TIntermSequence *copySeq = new TIntermSequence();
660 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400661 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
662 copyNode->mFunctionInfo = mFunctionInfo;
Olli Etuahofe486322017-03-21 09:30:54 +0000663 copyNode->setLine(mLine);
664 return copyNode;
665}
666
Olli Etuahob6fa0432016-09-28 16:28:05 +0100667TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
668{
669 TIntermTyped *operandCopy = node.mOperand->deepCopy();
670 ASSERT(operandCopy != nullptr);
671 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000672 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100673}
674
Olli Etuahod7a25242015-08-18 13:49:45 +0300675TIntermBinary::TIntermBinary(const TIntermBinary &node)
676 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
677{
678 TIntermTyped *leftCopy = node.mLeft->deepCopy();
679 TIntermTyped *rightCopy = node.mRight->deepCopy();
680 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
681 mLeft = leftCopy;
682 mRight = rightCopy;
683}
684
685TIntermUnary::TIntermUnary(const TIntermUnary &node)
686 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
687{
688 TIntermTyped *operandCopy = node.mOperand->deepCopy();
689 ASSERT(operandCopy != nullptr);
690 mOperand = operandCopy;
691}
692
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300693TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300694{
Olli Etuahod7a25242015-08-18 13:49:45 +0300695 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300696 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
697 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300698 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300699 mCondition = conditionCopy;
700 mTrueExpression = trueCopy;
701 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300702}
703
Jamie Madillb1a85f42014-08-19 15:23:24 -0400704bool TIntermOperator::isAssignment() const
705{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300706 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400707}
708
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300709bool TIntermOperator::isMultiplication() const
710{
711 switch (mOp)
712 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500713 case EOpMul:
714 case EOpMatrixTimesMatrix:
715 case EOpMatrixTimesVector:
716 case EOpMatrixTimesScalar:
717 case EOpVectorTimesMatrix:
718 case EOpVectorTimesScalar:
719 return true;
720 default:
721 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300722 }
723}
724
Jamie Madillb1a85f42014-08-19 15:23:24 -0400725bool TIntermOperator::isConstructor() const
726{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300727 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400728}
729
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800730bool TIntermOperator::isFunctionCall() const
731{
732 switch (mOp)
733 {
734 case EOpCallFunctionInAST:
735 case EOpCallBuiltInFunction:
736 case EOpCallInternalRawFunction:
737 return true;
738 default:
739 return false;
740 }
741}
742
Olli Etuaho1dded802016-08-18 18:13:13 +0300743TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
744{
745 if (left.isMatrix())
746 {
747 if (right.isMatrix())
748 {
749 return EOpMatrixTimesMatrix;
750 }
751 else
752 {
753 if (right.isVector())
754 {
755 return EOpMatrixTimesVector;
756 }
757 else
758 {
759 return EOpMatrixTimesScalar;
760 }
761 }
762 }
763 else
764 {
765 if (right.isMatrix())
766 {
767 if (left.isVector())
768 {
769 return EOpVectorTimesMatrix;
770 }
771 else
772 {
773 return EOpMatrixTimesScalar;
774 }
775 }
776 else
777 {
778 // Neither operand is a matrix.
779 if (left.isVector() == right.isVector())
780 {
781 // Leave as component product.
782 return EOpMul;
783 }
784 else
785 {
786 return EOpVectorTimesScalar;
787 }
788 }
789 }
790}
791
792TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
793{
794 if (left.isMatrix())
795 {
796 if (right.isMatrix())
797 {
798 return EOpMatrixTimesMatrixAssign;
799 }
800 else
801 {
802 // right should be scalar, but this may not be validated yet.
803 return EOpMatrixTimesScalarAssign;
804 }
805 }
806 else
807 {
808 if (right.isMatrix())
809 {
810 // Left should be a vector, but this may not be validated yet.
811 return EOpVectorTimesMatrixAssign;
812 }
813 else
814 {
815 // Neither operand is a matrix.
816 if (left.isVector() == right.isVector())
817 {
818 // Leave as component product.
819 return EOpMulAssign;
820 }
821 else
822 {
823 // left should be vector and right should be scalar, but this may not be validated
824 // yet.
825 return EOpVectorTimesScalarAssign;
826 }
827 }
828 }
829}
830
Jamie Madillb1a85f42014-08-19 15:23:24 -0400831//
832// Make sure the type of a unary operator is appropriate for its
833// combination of operation and operand type.
834//
Olli Etuahoa2234302016-08-31 12:05:39 +0300835void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400836{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300837 if (mOp == EOpArrayLength)
838 {
839 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
840 setType(TType(EbtInt, EbpUndefined, EvqConst));
841 return;
842 }
843
Olli Etuahoa2234302016-08-31 12:05:39 +0300844 TQualifier resultQualifier = EvqTemporary;
845 if (mOperand->getQualifier() == EvqConst)
846 resultQualifier = EvqConst;
847
848 unsigned char operandPrimarySize =
849 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400850 switch (mOp)
851 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300852 case EOpFloatBitsToInt:
853 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
854 break;
855 case EOpFloatBitsToUint:
856 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
857 break;
858 case EOpIntBitsToFloat:
859 case EOpUintBitsToFloat:
860 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
861 break;
862 case EOpPackSnorm2x16:
863 case EOpPackUnorm2x16:
864 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800865 case EOpPackUnorm4x8:
866 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300867 setType(TType(EbtUInt, EbpHigh, resultQualifier));
868 break;
869 case EOpUnpackSnorm2x16:
870 case EOpUnpackUnorm2x16:
871 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
872 break;
873 case EOpUnpackHalf2x16:
874 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
875 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800876 case EOpUnpackUnorm4x8:
877 case EOpUnpackSnorm4x8:
878 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
879 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300880 case EOpAny:
881 case EOpAll:
882 setType(TType(EbtBool, EbpUndefined, resultQualifier));
883 break;
884 case EOpLength:
885 case EOpDeterminant:
886 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
887 break;
888 case EOpTranspose:
889 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
890 static_cast<unsigned char>(mOperand->getType().getRows()),
891 static_cast<unsigned char>(mOperand->getType().getCols())));
892 break;
893 case EOpIsInf:
894 case EOpIsNan:
895 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
896 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000897 case EOpBitfieldReverse:
898 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
899 break;
900 case EOpBitCount:
901 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
902 break;
903 case EOpFindLSB:
904 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
905 break;
906 case EOpFindMSB:
907 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
908 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300909 default:
910 setType(mOperand->getType());
911 mType.setQualifier(resultQualifier);
912 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400913 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300914}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400915
Olli Etuahob6fa0432016-09-28 16:28:05 +0100916TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
917 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
918 mOperand(operand),
919 mSwizzleOffsets(swizzleOffsets)
920{
921 ASSERT(mSwizzleOffsets.size() <= 4);
922 promote();
923}
924
Olli Etuahoa2234302016-08-31 12:05:39 +0300925TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
926 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
927{
928 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400929}
930
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300931TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
932 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
933{
934 promote();
935}
936
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000937TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
938 : TIntermNode(), mSymbol(symbol)
939{
940 ASSERT(symbol);
941 setLine(line);
942}
943
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300944TIntermTernary::TIntermTernary(TIntermTyped *cond,
945 TIntermTyped *trueExpression,
946 TIntermTyped *falseExpression)
947 : TIntermTyped(trueExpression->getType()),
948 mCondition(cond),
949 mTrueExpression(trueExpression),
950 mFalseExpression(falseExpression)
951{
952 getTypePointer()->setQualifier(
953 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
954}
955
Olli Etuaho81629262017-04-19 11:56:01 +0300956TIntermLoop::TIntermLoop(TLoopType type,
957 TIntermNode *init,
958 TIntermTyped *cond,
959 TIntermTyped *expr,
960 TIntermBlock *body)
961 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
962{
963 // Declaration nodes with no children can appear if all the declarators just added constants to
964 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
965 if (mInit && mInit->getAsDeclarationNode() &&
966 mInit->getAsDeclarationNode()->getSequence()->empty())
967 {
968 mInit = nullptr;
969 }
970}
971
Olli Etuaho923ecef2017-10-11 12:01:38 +0300972TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
973 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
974{
975 // Prune empty false blocks so that there won't be unnecessary operations done on it.
976 if (mFalseBlock && mFalseBlock->getSequence()->empty())
977 {
978 mFalseBlock = nullptr;
979 }
980}
981
982TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
983 : TIntermNode(), mInit(init), mStatementList(statementList)
984{
985 ASSERT(mStatementList);
986}
987
988void TIntermSwitch::setStatementList(TIntermBlock *statementList)
989{
990 ASSERT(statementList);
991 mStatementList = statementList;
992}
993
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300994// static
995TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
996 TIntermTyped *trueExpression,
997 TIntermTyped *falseExpression)
998{
999 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1000 falseExpression->getQualifier() == EvqConst)
1001 {
1002 return EvqConst;
1003 }
1004 return EvqTemporary;
1005}
1006
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001007TIntermTyped *TIntermTernary::fold()
1008{
1009 if (mCondition->getAsConstantUnion())
1010 {
1011 if (mCondition->getAsConstantUnion()->getBConst(0))
1012 {
1013 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
1014 return mTrueExpression;
1015 }
1016 else
1017 {
1018 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
1019 return mFalseExpression;
1020 }
1021 }
1022 return this;
1023}
1024
Olli Etuahob6fa0432016-09-28 16:28:05 +01001025void TIntermSwizzle::promote()
1026{
1027 TQualifier resultQualifier = EvqTemporary;
1028 if (mOperand->getQualifier() == EvqConst)
1029 resultQualifier = EvqConst;
1030
1031 auto numFields = mSwizzleOffsets.size();
1032 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1033 static_cast<unsigned char>(numFields)));
1034}
1035
1036bool TIntermSwizzle::hasDuplicateOffsets() const
1037{
1038 int offsetCount[4] = {0u, 0u, 0u, 0u};
1039 for (const auto offset : mSwizzleOffsets)
1040 {
1041 offsetCount[offset]++;
1042 if (offsetCount[offset] > 1)
1043 {
1044 return true;
1045 }
1046 }
1047 return false;
1048}
1049
Olli Etuaho09b04a22016-12-15 13:30:26 +00001050bool TIntermSwizzle::offsetsMatch(int offset) const
1051{
1052 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1053}
1054
Olli Etuahob6fa0432016-09-28 16:28:05 +01001055void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1056{
1057 for (const int offset : mSwizzleOffsets)
1058 {
1059 switch (offset)
1060 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001061 case 0:
1062 *out << "x";
1063 break;
1064 case 1:
1065 *out << "y";
1066 break;
1067 case 2:
1068 *out << "z";
1069 break;
1070 case 3:
1071 *out << "w";
1072 break;
1073 default:
1074 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001075 }
1076 }
1077}
1078
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001079TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1080 const TIntermTyped *left,
1081 const TIntermTyped *right)
1082{
1083 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1084 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1085 right->getQualifier() != EvqConst)
1086 {
1087 return EvqTemporary;
1088 }
1089 return EvqConst;
1090}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001091
1092// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001093void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001094{
Olli Etuaho1dded802016-08-18 18:13:13 +03001095 ASSERT(!isMultiplication() ||
1096 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1097
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001098 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1099 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001100 if (mOp == EOpComma)
1101 {
1102 setType(mRight->getType());
1103 return;
1104 }
1105
Jamie Madillb1a85f42014-08-19 15:23:24 -04001106 // Base assumption: just make the type the same as the left
1107 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001108 setType(mLeft->getType());
1109
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001110 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001111 // Binary operations results in temporary variables unless both
1112 // operands are const.
1113 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1114 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001115 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001116 getTypePointer()->setQualifier(EvqTemporary);
1117 }
1118
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001119 // Handle indexing ops.
1120 switch (mOp)
1121 {
1122 case EOpIndexDirect:
1123 case EOpIndexIndirect:
1124 if (mLeft->isArray())
1125 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001126 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001127 }
1128 else if (mLeft->isMatrix())
1129 {
1130 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1131 static_cast<unsigned char>(mLeft->getRows())));
1132 }
1133 else if (mLeft->isVector())
1134 {
1135 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1136 }
1137 else
1138 {
1139 UNREACHABLE();
1140 }
1141 return;
1142 case EOpIndexDirectStruct:
1143 {
1144 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1145 const int i = mRight->getAsConstantUnion()->getIConst(0);
1146 setType(*fields[i]->type());
1147 getTypePointer()->setQualifier(resultQualifier);
1148 return;
1149 }
1150 case EOpIndexDirectInterfaceBlock:
1151 {
1152 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1153 const int i = mRight->getAsConstantUnion()->getIConst(0);
1154 setType(*fields[i]->type());
1155 getTypePointer()->setQualifier(resultQualifier);
1156 return;
1157 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001158 default:
1159 break;
1160 }
1161
1162 ASSERT(mLeft->isArray() == mRight->isArray());
1163
1164 // The result gets promoted to the highest precision.
1165 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1166 getTypePointer()->setPrecision(higherPrecision);
1167
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001168 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001169
1170 //
1171 // All scalars or structs. Code after this test assumes this case is removed!
1172 //
1173 if (nominalSize == 1)
1174 {
1175 switch (mOp)
1176 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001177 //
1178 // Promote to conditional
1179 //
1180 case EOpEqual:
1181 case EOpNotEqual:
1182 case EOpLessThan:
1183 case EOpGreaterThan:
1184 case EOpLessThanEqual:
1185 case EOpGreaterThanEqual:
1186 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1187 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001188
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001189 //
1190 // And and Or operate on conditionals
1191 //
1192 case EOpLogicalAnd:
1193 case EOpLogicalXor:
1194 case EOpLogicalOr:
1195 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1196 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1197 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001198
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001199 default:
1200 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001201 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001202 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001203 }
1204
1205 // If we reach here, at least one of the operands is vector or matrix.
1206 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001207 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001208
Jamie Madillb1a85f42014-08-19 15:23:24 -04001209 switch (mOp)
1210 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001211 case EOpMul:
1212 break;
1213 case EOpMatrixTimesScalar:
1214 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001215 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001216 setType(TType(basicType, higherPrecision, resultQualifier,
1217 static_cast<unsigned char>(mRight->getCols()),
1218 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001219 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001220 break;
1221 case EOpMatrixTimesVector:
1222 setType(TType(basicType, higherPrecision, resultQualifier,
1223 static_cast<unsigned char>(mLeft->getRows()), 1));
1224 break;
1225 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001226 setType(TType(basicType, higherPrecision, resultQualifier,
1227 static_cast<unsigned char>(mRight->getCols()),
1228 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001229 break;
1230 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001231 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001232 static_cast<unsigned char>(nominalSize), 1));
1233 break;
1234 case EOpVectorTimesMatrix:
1235 setType(TType(basicType, higherPrecision, resultQualifier,
1236 static_cast<unsigned char>(mRight->getCols()), 1));
1237 break;
1238 case EOpMulAssign:
1239 case EOpVectorTimesScalarAssign:
1240 case EOpVectorTimesMatrixAssign:
1241 case EOpMatrixTimesScalarAssign:
1242 case EOpMatrixTimesMatrixAssign:
1243 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1244 break;
1245 case EOpAssign:
1246 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001247 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1248 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1249 break;
1250 case EOpAdd:
1251 case EOpSub:
1252 case EOpDiv:
1253 case EOpIMod:
1254 case EOpBitShiftLeft:
1255 case EOpBitShiftRight:
1256 case EOpBitwiseAnd:
1257 case EOpBitwiseXor:
1258 case EOpBitwiseOr:
1259 case EOpAddAssign:
1260 case EOpSubAssign:
1261 case EOpDivAssign:
1262 case EOpIModAssign:
1263 case EOpBitShiftLeftAssign:
1264 case EOpBitShiftRightAssign:
1265 case EOpBitwiseAndAssign:
1266 case EOpBitwiseXorAssign:
1267 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001268 {
1269 const int secondarySize =
1270 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1271 setType(TType(basicType, higherPrecision, resultQualifier,
1272 static_cast<unsigned char>(nominalSize),
1273 static_cast<unsigned char>(secondarySize)));
1274 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001275 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001276 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001277 case EOpEqual:
1278 case EOpNotEqual:
1279 case EOpLessThan:
1280 case EOpGreaterThan:
1281 case EOpLessThanEqual:
1282 case EOpGreaterThanEqual:
1283 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1284 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001285 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001286 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001287
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001288 case EOpIndexDirect:
1289 case EOpIndexIndirect:
1290 case EOpIndexDirectInterfaceBlock:
1291 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001292 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001293 UNREACHABLE();
1294 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001295 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001296 UNREACHABLE();
1297 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001298 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001299}
1300
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001301const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001302{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001303 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001304 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001305 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001306 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001307 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001308 size_t arrayElementSize = arrayElementType.getObjectSize();
1309 return &mUnionArrayPointer[arrayElementSize * index];
1310 }
1311 else if (isMatrix())
1312 {
1313 ASSERT(index < getType().getCols());
1314 int size = getType().getRows();
1315 return &mUnionArrayPointer[size * index];
1316 }
1317 else if (isVector())
1318 {
1319 ASSERT(index < getType().getNominalSize());
1320 return &mUnionArrayPointer[index];
1321 }
1322 else
1323 {
1324 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001325 return nullptr;
1326 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001327}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001328
Olli Etuahob6fa0432016-09-28 16:28:05 +01001329TIntermTyped *TIntermSwizzle::fold()
1330{
1331 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1332 if (operandConstant == nullptr)
1333 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001334 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001335 }
1336
1337 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1338 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1339 {
1340 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1341 }
1342 return CreateFoldedNode(constArray, this, mType.getQualifier());
1343}
1344
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001345TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1346{
1347 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1348 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1349 switch (mOp)
1350 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001351 case EOpComma:
1352 {
1353 if (mLeft->hasSideEffects())
1354 {
1355 return this;
1356 }
1357 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1358 return mRight;
1359 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001360 case EOpIndexDirect:
1361 {
1362 if (leftConstant == nullptr || rightConstant == nullptr)
1363 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001364 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001365 }
1366 int index = rightConstant->getIConst(0);
1367
1368 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001369 if (!constArray)
1370 {
1371 return this;
1372 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001373 return CreateFoldedNode(constArray, this, mType.getQualifier());
1374 }
1375 case EOpIndexDirectStruct:
1376 {
1377 if (leftConstant == nullptr || rightConstant == nullptr)
1378 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001379 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001380 }
1381 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1382 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1383
1384 size_t previousFieldsSize = 0;
1385 for (size_t i = 0; i < index; ++i)
1386 {
1387 previousFieldsSize += fields[i]->type()->getObjectSize();
1388 }
1389
1390 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1391 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1392 }
1393 case EOpIndexIndirect:
1394 case EOpIndexDirectInterfaceBlock:
1395 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001396 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001397 default:
1398 {
1399 if (leftConstant == nullptr || rightConstant == nullptr)
1400 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001401 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001402 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001403 TConstantUnion *constArray =
1404 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001405 if (!constArray)
1406 {
1407 return this;
1408 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001409
1410 // Nodes may be constant folded without being qualified as constant.
1411 return CreateFoldedNode(constArray, this, mType.getQualifier());
1412 }
1413 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001414}
1415
Olli Etuahof119a262016-08-19 15:54:22 +03001416TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001417{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301418 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001419
1420 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301421 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001422 // The size of runtime-sized arrays may only be determined at runtime.
1423 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001424 {
1425 return this;
1426 }
1427 constArray = new TConstantUnion[1];
1428 constArray->setIConst(mOperand->getOutermostArraySize());
1429 }
1430 else
1431 {
1432 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1433 if (operandConstant == nullptr)
1434 {
1435 return this;
1436 }
1437
1438 switch (mOp)
1439 {
1440 case EOpAny:
1441 case EOpAll:
1442 case EOpLength:
1443 case EOpTranspose:
1444 case EOpDeterminant:
1445 case EOpInverse:
1446 case EOpPackSnorm2x16:
1447 case EOpUnpackSnorm2x16:
1448 case EOpPackUnorm2x16:
1449 case EOpUnpackUnorm2x16:
1450 case EOpPackHalf2x16:
1451 case EOpUnpackHalf2x16:
1452 case EOpPackUnorm4x8:
1453 case EOpPackSnorm4x8:
1454 case EOpUnpackUnorm4x8:
1455 case EOpUnpackSnorm4x8:
1456 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1457 break;
1458 default:
1459 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1460 break;
1461 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301462 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001463 if (constArray == nullptr)
1464 {
1465 return this;
1466 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001467
1468 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001469 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001470}
1471
Olli Etuahof119a262016-08-19 15:54:22 +03001472TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001473{
1474 // Make sure that all params are constant before actual constant folding.
1475 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001476 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001477 if (param->getAsConstantUnion() == nullptr)
1478 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001479 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001480 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001481 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001482 TConstantUnion *constArray = nullptr;
1483 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001484 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001485 else
Olli Etuahof119a262016-08-19 15:54:22 +03001486 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001487
1488 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001489 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001490}
1491
Jamie Madillb1a85f42014-08-19 15:23:24 -04001492//
1493// The fold functions see if an operation on a constant can be done in place,
1494// without generating run-time code.
1495//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001496// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001497//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001498TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1499 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001500 TDiagnostics *diagnostics,
1501 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001502{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001503 const TConstantUnion *leftArray = getUnionArrayPointer();
1504 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001505
Olli Etuahof119a262016-08-19 15:54:22 +03001506 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001507
1508 size_t objectSize = getType().getObjectSize();
1509
1510 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1511 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1512 {
1513 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1514 }
1515 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1516 {
1517 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001518 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001519 objectSize = rightNode->getType().getObjectSize();
1520 }
1521
1522 TConstantUnion *resultArray = nullptr;
1523
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001524 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001525 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001526 case EOpAdd:
1527 resultArray = new TConstantUnion[objectSize];
1528 for (size_t i = 0; i < objectSize; i++)
1529 resultArray[i] =
1530 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1531 break;
1532 case EOpSub:
1533 resultArray = new TConstantUnion[objectSize];
1534 for (size_t i = 0; i < objectSize; i++)
1535 resultArray[i] =
1536 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1537 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001538
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001539 case EOpMul:
1540 case EOpVectorTimesScalar:
1541 case EOpMatrixTimesScalar:
1542 resultArray = new TConstantUnion[objectSize];
1543 for (size_t i = 0; i < objectSize; i++)
1544 resultArray[i] =
1545 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1546 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001547
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001548 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001549 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001550 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001551 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001552
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001553 const int leftCols = getCols();
1554 const int leftRows = getRows();
1555 const int rightCols = rightNode->getType().getCols();
1556 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001557 const int resultCols = rightCols;
1558 const int resultRows = leftRows;
1559
1560 resultArray = new TConstantUnion[resultCols * resultRows];
1561 for (int row = 0; row < resultRows; row++)
1562 {
1563 for (int column = 0; column < resultCols; column++)
1564 {
1565 resultArray[resultRows * column + row].setFConst(0.0f);
1566 for (int i = 0; i < leftCols; i++)
1567 {
1568 resultArray[resultRows * column + row].setFConst(
1569 resultArray[resultRows * column + row].getFConst() +
1570 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001571 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001572 }
1573 }
1574 }
1575 }
1576 break;
1577
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001578 case EOpDiv:
1579 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001580 {
1581 resultArray = new TConstantUnion[objectSize];
1582 for (size_t i = 0; i < objectSize; i++)
1583 {
1584 switch (getType().getBasicType())
1585 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001586 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001587 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001588 ASSERT(op == EOpDiv);
1589 float dividend = leftArray[i].getFConst();
1590 float divisor = rightArray[i].getFConst();
1591 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001592 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001593 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001594 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001595 diagnostics->warning(
1596 getLine(),
1597 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001598 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001599 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001600 }
1601 else
1602 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001603 diagnostics->warning(getLine(),
1604 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001605 bool negativeResult =
1606 std::signbit(dividend) != std::signbit(divisor);
1607 resultArray[i].setFConst(
1608 negativeResult ? -std::numeric_limits<float>::infinity()
1609 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001610 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001611 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001612 else if (gl::isInf(dividend) && gl::isInf(divisor))
1613 {
1614 diagnostics->warning(getLine(),
1615 "Infinity divided by infinity during constant "
1616 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001617 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1619 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001620 else
1621 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001622 float result = dividend / divisor;
1623 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001624 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001625 diagnostics->warning(
1626 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001627 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001628 }
1629 resultArray[i].setFConst(result);
1630 }
1631 break;
1632 }
1633 case EbtInt:
1634 if (rightArray[i] == 0)
1635 {
1636 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001637 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001638 resultArray[i].setIConst(INT_MAX);
1639 }
1640 else
1641 {
1642 int lhs = leftArray[i].getIConst();
1643 int divisor = rightArray[i].getIConst();
1644 if (op == EOpDiv)
1645 {
1646 // Check for the special case where the minimum representable number
1647 // is
1648 // divided by -1. If left alone this leads to integer overflow in
1649 // C++.
1650 // ESSL 3.00.6 section 4.1.3 Integers:
1651 // "However, for the case where the minimum representable value is
1652 // divided by -1, it is allowed to return either the minimum
1653 // representable value or the maximum representable value."
1654 if (lhs == -0x7fffffff - 1 && divisor == -1)
1655 {
1656 resultArray[i].setIConst(0x7fffffff);
1657 }
1658 else
1659 {
1660 resultArray[i].setIConst(lhs / divisor);
1661 }
Olli Etuahod4453572016-09-27 13:21:46 +01001662 }
1663 else
1664 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001665 ASSERT(op == EOpIMod);
1666 if (lhs < 0 || divisor < 0)
1667 {
1668 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1669 // when
1670 // either one of the operands is negative.
1671 diagnostics->warning(getLine(),
1672 "Negative modulus operator operand "
1673 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001674 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001675 resultArray[i].setIConst(0);
1676 }
1677 else
1678 {
1679 resultArray[i].setIConst(lhs % divisor);
1680 }
Olli Etuahod4453572016-09-27 13:21:46 +01001681 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001682 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001683 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001684
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001685 case EbtUInt:
1686 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001687 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001688 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001689 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001690 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001691 }
1692 else
1693 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001694 if (op == EOpDiv)
1695 {
1696 resultArray[i].setUConst(leftArray[i].getUConst() /
1697 rightArray[i].getUConst());
1698 }
1699 else
1700 {
1701 ASSERT(op == EOpIMod);
1702 resultArray[i].setUConst(leftArray[i].getUConst() %
1703 rightArray[i].getUConst());
1704 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001705 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001706 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001707
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001708 default:
1709 UNREACHABLE();
1710 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001711 }
1712 }
1713 }
1714 break;
1715
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001716 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001717 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001718 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001719 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001720
1721 const int matrixCols = getCols();
1722 const int matrixRows = getRows();
1723
1724 resultArray = new TConstantUnion[matrixRows];
1725
1726 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1727 {
1728 resultArray[matrixRow].setFConst(0.0f);
1729 for (int col = 0; col < matrixCols; col++)
1730 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001731 resultArray[matrixRow].setFConst(
1732 resultArray[matrixRow].getFConst() +
1733 leftArray[col * matrixRows + matrixRow].getFConst() *
1734 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001735 }
1736 }
1737 }
1738 break;
1739
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001740 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001741 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001742 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001743 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001744
1745 const int matrixCols = rightNode->getType().getCols();
1746 const int matrixRows = rightNode->getType().getRows();
1747
1748 resultArray = new TConstantUnion[matrixCols];
1749
1750 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1751 {
1752 resultArray[matrixCol].setFConst(0.0f);
1753 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1754 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001755 resultArray[matrixCol].setFConst(
1756 resultArray[matrixCol].getFConst() +
1757 leftArray[matrixRow].getFConst() *
1758 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001759 }
1760 }
1761 }
1762 break;
1763
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001764 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001765 {
1766 resultArray = new TConstantUnion[objectSize];
1767 for (size_t i = 0; i < objectSize; i++)
1768 {
1769 resultArray[i] = leftArray[i] && rightArray[i];
1770 }
1771 }
1772 break;
1773
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001774 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001775 {
1776 resultArray = new TConstantUnion[objectSize];
1777 for (size_t i = 0; i < objectSize; i++)
1778 {
1779 resultArray[i] = leftArray[i] || rightArray[i];
1780 }
1781 }
1782 break;
1783
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001784 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001785 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001786 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001787 resultArray = new TConstantUnion[objectSize];
1788 for (size_t i = 0; i < objectSize; i++)
1789 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001790 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001791 }
1792 }
1793 break;
1794
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001795 case EOpBitwiseAnd:
1796 resultArray = new TConstantUnion[objectSize];
1797 for (size_t i = 0; i < objectSize; i++)
1798 resultArray[i] = leftArray[i] & rightArray[i];
1799 break;
1800 case EOpBitwiseXor:
1801 resultArray = new TConstantUnion[objectSize];
1802 for (size_t i = 0; i < objectSize; i++)
1803 resultArray[i] = leftArray[i] ^ rightArray[i];
1804 break;
1805 case EOpBitwiseOr:
1806 resultArray = new TConstantUnion[objectSize];
1807 for (size_t i = 0; i < objectSize; i++)
1808 resultArray[i] = leftArray[i] | rightArray[i];
1809 break;
1810 case EOpBitShiftLeft:
1811 resultArray = new TConstantUnion[objectSize];
1812 for (size_t i = 0; i < objectSize; i++)
1813 resultArray[i] =
1814 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1815 break;
1816 case EOpBitShiftRight:
1817 resultArray = new TConstantUnion[objectSize];
1818 for (size_t i = 0; i < objectSize; i++)
1819 resultArray[i] =
1820 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1821 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001822
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001823 case EOpLessThan:
1824 ASSERT(objectSize == 1);
1825 resultArray = new TConstantUnion[1];
1826 resultArray->setBConst(*leftArray < *rightArray);
1827 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001828
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001829 case EOpGreaterThan:
1830 ASSERT(objectSize == 1);
1831 resultArray = new TConstantUnion[1];
1832 resultArray->setBConst(*leftArray > *rightArray);
1833 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001834
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001835 case EOpLessThanEqual:
1836 ASSERT(objectSize == 1);
1837 resultArray = new TConstantUnion[1];
1838 resultArray->setBConst(!(*leftArray > *rightArray));
1839 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001840
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001841 case EOpGreaterThanEqual:
1842 ASSERT(objectSize == 1);
1843 resultArray = new TConstantUnion[1];
1844 resultArray->setBConst(!(*leftArray < *rightArray));
1845 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001846
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001847 case EOpEqual:
1848 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001849 {
1850 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001851 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001852 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001853 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001854 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001855 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001856 equal = false;
1857 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001858 }
1859 }
1860 if (op == EOpEqual)
1861 {
1862 resultArray->setBConst(equal);
1863 }
1864 else
1865 {
1866 resultArray->setBConst(!equal);
1867 }
1868 }
1869 break;
1870
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001871 default:
1872 UNREACHABLE();
1873 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001874 }
1875 return resultArray;
1876}
1877
Olli Etuahof119a262016-08-19 15:54:22 +03001878// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1879// code. Returns the constant value to keep using. Nullptr should not be returned.
1880TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001881{
Olli Etuahof119a262016-08-19 15:54:22 +03001882 // Do operations where the return type may have a different number of components compared to the
1883 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001884
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001885 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001886 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301887
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001888 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301889 TConstantUnion *resultArray = nullptr;
1890 switch (op)
1891 {
Olli Etuahof119a262016-08-19 15:54:22 +03001892 case EOpAny:
1893 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301894 resultArray = new TConstantUnion();
1895 resultArray->setBConst(false);
1896 for (size_t i = 0; i < objectSize; i++)
1897 {
1898 if (operandArray[i].getBConst())
1899 {
1900 resultArray->setBConst(true);
1901 break;
1902 }
1903 }
1904 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301905
Olli Etuahof119a262016-08-19 15:54:22 +03001906 case EOpAll:
1907 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301908 resultArray = new TConstantUnion();
1909 resultArray->setBConst(true);
1910 for (size_t i = 0; i < objectSize; i++)
1911 {
1912 if (!operandArray[i].getBConst())
1913 {
1914 resultArray->setBConst(false);
1915 break;
1916 }
1917 }
1918 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301919
Olli Etuahof119a262016-08-19 15:54:22 +03001920 case EOpLength:
1921 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301922 resultArray = new TConstantUnion();
1923 resultArray->setFConst(VectorLength(operandArray, objectSize));
1924 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301925
Olli Etuahof119a262016-08-19 15:54:22 +03001926 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301927 {
Olli Etuahof119a262016-08-19 15:54:22 +03001928 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301929 resultArray = new TConstantUnion[objectSize];
1930 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001931 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301932 SetUnionArrayFromMatrix(result, resultArray);
1933 break;
1934 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301935
Olli Etuahof119a262016-08-19 15:54:22 +03001936 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301937 {
Olli Etuahof119a262016-08-19 15:54:22 +03001938 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301939 unsigned int size = getType().getNominalSize();
1940 ASSERT(size >= 2 && size <= 4);
1941 resultArray = new TConstantUnion();
1942 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1943 break;
1944 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945
Olli Etuahof119a262016-08-19 15:54:22 +03001946 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301947 {
Olli Etuahof119a262016-08-19 15:54:22 +03001948 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301949 unsigned int size = getType().getNominalSize();
1950 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001951 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301952 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1953 SetUnionArrayFromMatrix(result, resultArray);
1954 break;
1955 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301956
Olli Etuahof119a262016-08-19 15:54:22 +03001957 case EOpPackSnorm2x16:
1958 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301959 ASSERT(getType().getNominalSize() == 2);
1960 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001961 resultArray->setUConst(
1962 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301963 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301964
Olli Etuahof119a262016-08-19 15:54:22 +03001965 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301966 {
Olli Etuahof119a262016-08-19 15:54:22 +03001967 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301968 resultArray = new TConstantUnion[2];
1969 float f1, f2;
1970 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1971 resultArray[0].setFConst(f1);
1972 resultArray[1].setFConst(f2);
1973 break;
1974 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301975
Olli Etuahof119a262016-08-19 15:54:22 +03001976 case EOpPackUnorm2x16:
1977 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301978 ASSERT(getType().getNominalSize() == 2);
1979 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001980 resultArray->setUConst(
1981 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301982 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301983
Olli Etuahof119a262016-08-19 15:54:22 +03001984 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301985 {
Olli Etuahof119a262016-08-19 15:54:22 +03001986 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301987 resultArray = new TConstantUnion[2];
1988 float f1, f2;
1989 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1990 resultArray[0].setFConst(f1);
1991 resultArray[1].setFConst(f2);
1992 break;
1993 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301994
Olli Etuahof119a262016-08-19 15:54:22 +03001995 case EOpPackHalf2x16:
1996 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301997 ASSERT(getType().getNominalSize() == 2);
1998 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001999 resultArray->setUConst(
2000 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302001 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302002
Olli Etuahof119a262016-08-19 15:54:22 +03002003 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302004 {
Olli Etuahof119a262016-08-19 15:54:22 +03002005 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302006 resultArray = new TConstantUnion[2];
2007 float f1, f2;
2008 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2009 resultArray[0].setFConst(f1);
2010 resultArray[1].setFConst(f2);
2011 break;
2012 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302013
Olli Etuaho25aef452017-01-29 16:15:44 -08002014 case EOpPackUnorm4x8:
2015 {
2016 ASSERT(getType().getBasicType() == EbtFloat);
2017 resultArray = new TConstantUnion();
2018 resultArray->setUConst(
2019 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2020 operandArray[2].getFConst(), operandArray[3].getFConst()));
2021 break;
2022 }
2023 case EOpPackSnorm4x8:
2024 {
2025 ASSERT(getType().getBasicType() == EbtFloat);
2026 resultArray = new TConstantUnion();
2027 resultArray->setUConst(
2028 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2029 operandArray[2].getFConst(), operandArray[3].getFConst()));
2030 break;
2031 }
2032 case EOpUnpackUnorm4x8:
2033 {
2034 ASSERT(getType().getBasicType() == EbtUInt);
2035 resultArray = new TConstantUnion[4];
2036 float f[4];
2037 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2038 for (size_t i = 0; i < 4; ++i)
2039 {
2040 resultArray[i].setFConst(f[i]);
2041 }
2042 break;
2043 }
2044 case EOpUnpackSnorm4x8:
2045 {
2046 ASSERT(getType().getBasicType() == EbtUInt);
2047 resultArray = new TConstantUnion[4];
2048 float f[4];
2049 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2050 for (size_t i = 0; i < 4; ++i)
2051 {
2052 resultArray[i].setFConst(f[i]);
2053 }
2054 break;
2055 }
2056
Olli Etuahof119a262016-08-19 15:54:22 +03002057 default:
2058 UNREACHABLE();
2059 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302060 }
2061
2062 return resultArray;
2063}
2064
Olli Etuahof119a262016-08-19 15:54:22 +03002065TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2066 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302067{
Olli Etuahof119a262016-08-19 15:54:22 +03002068 // Do unary operations where each component of the result is computed based on the corresponding
2069 // component of the operand. Also folds normalize, though the divisor in that case takes all
2070 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302071
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002072 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002073 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002074
2075 size_t objectSize = getType().getObjectSize();
2076
Arun Patoleab2b9a22015-07-06 18:27:56 +05302077 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2078 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302079 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002080 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302081 {
Olli Etuahof119a262016-08-19 15:54:22 +03002082 case EOpNegative:
2083 switch (getType().getBasicType())
2084 {
2085 case EbtFloat:
2086 resultArray[i].setFConst(-operandArray[i].getFConst());
2087 break;
2088 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002089 if (operandArray[i] == std::numeric_limits<int>::min())
2090 {
2091 // The minimum representable integer doesn't have a positive
2092 // counterpart, rather the negation overflows and in ESSL is supposed to
2093 // wrap back to the minimum representable integer. Make sure that we
2094 // don't actually let the negation overflow, which has undefined
2095 // behavior in C++.
2096 resultArray[i].setIConst(std::numeric_limits<int>::min());
2097 }
2098 else
2099 {
2100 resultArray[i].setIConst(-operandArray[i].getIConst());
2101 }
Olli Etuahof119a262016-08-19 15:54:22 +03002102 break;
2103 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002104 if (operandArray[i] == 0x80000000u)
2105 {
2106 resultArray[i].setUConst(0x80000000u);
2107 }
2108 else
2109 {
2110 resultArray[i].setUConst(static_cast<unsigned int>(
2111 -static_cast<int>(operandArray[i].getUConst())));
2112 }
Olli Etuahof119a262016-08-19 15:54:22 +03002113 break;
2114 default:
2115 UNREACHABLE();
2116 return nullptr;
2117 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302118 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302119
Olli Etuahof119a262016-08-19 15:54:22 +03002120 case EOpPositive:
2121 switch (getType().getBasicType())
2122 {
2123 case EbtFloat:
2124 resultArray[i].setFConst(operandArray[i].getFConst());
2125 break;
2126 case EbtInt:
2127 resultArray[i].setIConst(operandArray[i].getIConst());
2128 break;
2129 case EbtUInt:
2130 resultArray[i].setUConst(static_cast<unsigned int>(
2131 static_cast<int>(operandArray[i].getUConst())));
2132 break;
2133 default:
2134 UNREACHABLE();
2135 return nullptr;
2136 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302137 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302138
Olli Etuahof119a262016-08-19 15:54:22 +03002139 case EOpLogicalNot:
2140 switch (getType().getBasicType())
2141 {
2142 case EbtBool:
2143 resultArray[i].setBConst(!operandArray[i].getBConst());
2144 break;
2145 default:
2146 UNREACHABLE();
2147 return nullptr;
2148 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302149 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302150
Olli Etuahof119a262016-08-19 15:54:22 +03002151 case EOpBitwiseNot:
2152 switch (getType().getBasicType())
2153 {
2154 case EbtInt:
2155 resultArray[i].setIConst(~operandArray[i].getIConst());
2156 break;
2157 case EbtUInt:
2158 resultArray[i].setUConst(~operandArray[i].getUConst());
2159 break;
2160 default:
2161 UNREACHABLE();
2162 return nullptr;
2163 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302164 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302165
Olli Etuahof119a262016-08-19 15:54:22 +03002166 case EOpRadians:
2167 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302168 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2169 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302170
Olli Etuahof119a262016-08-19 15:54:22 +03002171 case EOpDegrees:
2172 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302173 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2174 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302175
Olli Etuahof119a262016-08-19 15:54:22 +03002176 case EOpSin:
2177 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302178 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302179
Olli Etuahof119a262016-08-19 15:54:22 +03002180 case EOpCos:
2181 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2182 break;
2183
2184 case EOpTan:
2185 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2186 break;
2187
2188 case EOpAsin:
2189 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2190 // 0.
2191 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2192 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2193 diagnostics, &resultArray[i]);
2194 else
2195 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2196 break;
2197
2198 case EOpAcos:
2199 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2200 // 0.
2201 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2202 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2203 diagnostics, &resultArray[i]);
2204 else
2205 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2206 break;
2207
2208 case EOpAtan:
2209 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2210 break;
2211
2212 case EOpSinh:
2213 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2214 break;
2215
2216 case EOpCosh:
2217 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2218 break;
2219
2220 case EOpTanh:
2221 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2222 break;
2223
2224 case EOpAsinh:
2225 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2226 break;
2227
2228 case EOpAcosh:
2229 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2230 if (operandArray[i].getFConst() < 1.0f)
2231 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2232 diagnostics, &resultArray[i]);
2233 else
2234 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2235 break;
2236
2237 case EOpAtanh:
2238 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2239 // 0.
2240 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2241 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2242 diagnostics, &resultArray[i]);
2243 else
2244 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2245 break;
2246
2247 case EOpAbs:
2248 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302249 {
Olli Etuahof119a262016-08-19 15:54:22 +03002250 case EbtFloat:
2251 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2252 break;
2253 case EbtInt:
2254 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2255 break;
2256 default:
2257 UNREACHABLE();
2258 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302259 }
2260 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002261
2262 case EOpSign:
2263 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302264 {
Olli Etuahof119a262016-08-19 15:54:22 +03002265 case EbtFloat:
2266 {
2267 float fConst = operandArray[i].getFConst();
2268 float fResult = 0.0f;
2269 if (fConst > 0.0f)
2270 fResult = 1.0f;
2271 else if (fConst < 0.0f)
2272 fResult = -1.0f;
2273 resultArray[i].setFConst(fResult);
2274 break;
2275 }
2276 case EbtInt:
2277 {
2278 int iConst = operandArray[i].getIConst();
2279 int iResult = 0;
2280 if (iConst > 0)
2281 iResult = 1;
2282 else if (iConst < 0)
2283 iResult = -1;
2284 resultArray[i].setIConst(iResult);
2285 break;
2286 }
2287 default:
2288 UNREACHABLE();
2289 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302290 }
2291 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302292
Olli Etuahof119a262016-08-19 15:54:22 +03002293 case EOpFloor:
2294 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2295 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302296
Olli Etuahof119a262016-08-19 15:54:22 +03002297 case EOpTrunc:
2298 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2299 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302300
Olli Etuahof119a262016-08-19 15:54:22 +03002301 case EOpRound:
2302 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2303 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302304
Olli Etuahof119a262016-08-19 15:54:22 +03002305 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302306 {
Olli Etuahof119a262016-08-19 15:54:22 +03002307 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302308 float x = operandArray[i].getFConst();
2309 float result;
2310 float fractPart = modff(x, &result);
2311 if (fabsf(fractPart) == 0.5f)
2312 result = 2.0f * roundf(x / 2.0f);
2313 else
2314 result = roundf(x);
2315 resultArray[i].setFConst(result);
2316 break;
2317 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302318
Olli Etuahof119a262016-08-19 15:54:22 +03002319 case EOpCeil:
2320 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2321 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302322
Olli Etuahof119a262016-08-19 15:54:22 +03002323 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302324 {
Olli Etuahof119a262016-08-19 15:54:22 +03002325 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302326 float x = operandArray[i].getFConst();
2327 resultArray[i].setFConst(x - floorf(x));
2328 break;
2329 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302330
Olli Etuahof119a262016-08-19 15:54:22 +03002331 case EOpIsNan:
2332 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302333 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2334 break;
Arun Patole551279e2015-07-07 18:18:23 +05302335
Olli Etuahof119a262016-08-19 15:54:22 +03002336 case EOpIsInf:
2337 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302338 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2339 break;
Arun Patole551279e2015-07-07 18:18:23 +05302340
Olli Etuahof119a262016-08-19 15:54:22 +03002341 case EOpFloatBitsToInt:
2342 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302343 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2344 break;
Arun Patole551279e2015-07-07 18:18:23 +05302345
Olli Etuahof119a262016-08-19 15:54:22 +03002346 case EOpFloatBitsToUint:
2347 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302348 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2349 break;
Arun Patole551279e2015-07-07 18:18:23 +05302350
Olli Etuahof119a262016-08-19 15:54:22 +03002351 case EOpIntBitsToFloat:
2352 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302353 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2354 break;
Arun Patole551279e2015-07-07 18:18:23 +05302355
Olli Etuahof119a262016-08-19 15:54:22 +03002356 case EOpUintBitsToFloat:
2357 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302358 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2359 break;
Arun Patole551279e2015-07-07 18:18:23 +05302360
Olli Etuahof119a262016-08-19 15:54:22 +03002361 case EOpExp:
2362 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2363 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302364
Olli Etuahof119a262016-08-19 15:54:22 +03002365 case EOpLog:
2366 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2367 if (operandArray[i].getFConst() <= 0.0f)
2368 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2369 diagnostics, &resultArray[i]);
2370 else
2371 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2372 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302373
Olli Etuahof119a262016-08-19 15:54:22 +03002374 case EOpExp2:
2375 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2376 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302377
Olli Etuahof119a262016-08-19 15:54:22 +03002378 case EOpLog2:
2379 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2380 // And log2f is not available on some plarforms like old android, so just using
2381 // log(x)/log(2) here.
2382 if (operandArray[i].getFConst() <= 0.0f)
2383 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2384 diagnostics, &resultArray[i]);
2385 else
2386 {
2387 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2388 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2389 }
2390 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302391
Olli Etuahof119a262016-08-19 15:54:22 +03002392 case EOpSqrt:
2393 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2394 if (operandArray[i].getFConst() < 0.0f)
2395 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2396 diagnostics, &resultArray[i]);
2397 else
2398 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2399 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302400
Olli Etuahof119a262016-08-19 15:54:22 +03002401 case EOpInverseSqrt:
2402 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2403 // so getting the square root first using builtin function sqrt() and then taking
2404 // its inverse.
2405 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2406 // result to 0.
2407 if (operandArray[i].getFConst() <= 0.0f)
2408 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2409 diagnostics, &resultArray[i]);
2410 else
2411 {
2412 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2413 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2414 }
2415 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302416
Olli Etuahod68924e2017-01-02 17:34:40 +00002417 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002418 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302419 resultArray[i].setBConst(!operandArray[i].getBConst());
2420 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302421
Olli Etuahof119a262016-08-19 15:54:22 +03002422 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302423 {
Olli Etuahof119a262016-08-19 15:54:22 +03002424 ASSERT(getType().getBasicType() == EbtFloat);
2425 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302426 float length = VectorLength(operandArray, objectSize);
2427 if (length)
2428 resultArray[i].setFConst(x / length);
2429 else
Olli Etuahof119a262016-08-19 15:54:22 +03002430 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2431 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302432 break;
2433 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002434 case EOpBitfieldReverse:
2435 {
2436 uint32_t value;
2437 if (getType().getBasicType() == EbtInt)
2438 {
2439 value = static_cast<uint32_t>(operandArray[i].getIConst());
2440 }
2441 else
2442 {
2443 ASSERT(getType().getBasicType() == EbtUInt);
2444 value = operandArray[i].getUConst();
2445 }
2446 uint32_t result = gl::BitfieldReverse(value);
2447 if (getType().getBasicType() == EbtInt)
2448 {
2449 resultArray[i].setIConst(static_cast<int32_t>(result));
2450 }
2451 else
2452 {
2453 resultArray[i].setUConst(result);
2454 }
2455 break;
2456 }
2457 case EOpBitCount:
2458 {
2459 uint32_t value;
2460 if (getType().getBasicType() == EbtInt)
2461 {
2462 value = static_cast<uint32_t>(operandArray[i].getIConst());
2463 }
2464 else
2465 {
2466 ASSERT(getType().getBasicType() == EbtUInt);
2467 value = operandArray[i].getUConst();
2468 }
2469 int result = gl::BitCount(value);
2470 resultArray[i].setIConst(result);
2471 break;
2472 }
2473 case EOpFindLSB:
2474 {
2475 uint32_t value;
2476 if (getType().getBasicType() == EbtInt)
2477 {
2478 value = static_cast<uint32_t>(operandArray[i].getIConst());
2479 }
2480 else
2481 {
2482 ASSERT(getType().getBasicType() == EbtUInt);
2483 value = operandArray[i].getUConst();
2484 }
2485 resultArray[i].setIConst(gl::FindLSB(value));
2486 break;
2487 }
2488 case EOpFindMSB:
2489 {
2490 uint32_t value;
2491 if (getType().getBasicType() == EbtInt)
2492 {
2493 int intValue = operandArray[i].getIConst();
2494 value = static_cast<uint32_t>(intValue);
2495 if (intValue < 0)
2496 {
2497 // Look for zero instead of one in value. This also handles the intValue ==
2498 // -1 special case, where the return value needs to be -1.
2499 value = ~value;
2500 }
2501 }
2502 else
2503 {
2504 ASSERT(getType().getBasicType() == EbtUInt);
2505 value = operandArray[i].getUConst();
2506 }
2507 resultArray[i].setIConst(gl::FindMSB(value));
2508 break;
2509 }
Olli Etuahof119a262016-08-19 15:54:22 +03002510 case EOpDFdx:
2511 case EOpDFdy:
2512 case EOpFwidth:
2513 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302514 // Derivatives of constant arguments should be 0.
2515 resultArray[i].setFConst(0.0f);
2516 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302517
Olli Etuahof119a262016-08-19 15:54:22 +03002518 default:
2519 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302520 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302521 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002522
Arun Patoleab2b9a22015-07-06 18:27:56 +05302523 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002524}
2525
Olli Etuahof119a262016-08-19 15:54:22 +03002526void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2527 FloatTypeUnaryFunc builtinFunc,
2528 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302529{
2530 ASSERT(builtinFunc);
2531
Olli Etuahof119a262016-08-19 15:54:22 +03002532 ASSERT(getType().getBasicType() == EbtFloat);
2533 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302534}
2535
Jamie Madillb1a85f42014-08-19 15:23:24 -04002536// static
Olli Etuahof119a262016-08-19 15:54:22 +03002537TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002538{
2539 ASSERT(aggregate->getSequence()->size() > 0u);
2540 size_t resultSize = aggregate->getType().getObjectSize();
2541 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2542 TBasicType basicType = aggregate->getBasicType();
2543
2544 size_t resultIndex = 0u;
2545
2546 if (aggregate->getSequence()->size() == 1u)
2547 {
2548 TIntermNode *argument = aggregate->getSequence()->front();
2549 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2550 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2551 // Check the special case of constructing a matrix diagonal from a single scalar,
2552 // or a vector from a single scalar.
2553 if (argumentConstant->getType().getObjectSize() == 1u)
2554 {
2555 if (aggregate->isMatrix())
2556 {
2557 int resultCols = aggregate->getType().getCols();
2558 int resultRows = aggregate->getType().getRows();
2559 for (int col = 0; col < resultCols; ++col)
2560 {
2561 for (int row = 0; row < resultRows; ++row)
2562 {
2563 if (col == row)
2564 {
2565 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2566 }
2567 else
2568 {
2569 resultArray[resultIndex].setFConst(0.0f);
2570 }
2571 ++resultIndex;
2572 }
2573 }
2574 }
2575 else
2576 {
2577 while (resultIndex < resultSize)
2578 {
2579 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2580 ++resultIndex;
2581 }
2582 }
2583 ASSERT(resultIndex == resultSize);
2584 return resultArray;
2585 }
2586 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2587 {
2588 // The special case of constructing a matrix from a matrix.
2589 int argumentCols = argumentConstant->getType().getCols();
2590 int argumentRows = argumentConstant->getType().getRows();
2591 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002592 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002593 for (int col = 0; col < resultCols; ++col)
2594 {
2595 for (int row = 0; row < resultRows; ++row)
2596 {
2597 if (col < argumentCols && row < argumentRows)
2598 {
2599 resultArray[resultIndex].cast(basicType,
2600 argumentUnionArray[col * argumentRows + row]);
2601 }
2602 else if (col == row)
2603 {
2604 resultArray[resultIndex].setFConst(1.0f);
2605 }
2606 else
2607 {
2608 resultArray[resultIndex].setFConst(0.0f);
2609 }
2610 ++resultIndex;
2611 }
2612 }
2613 ASSERT(resultIndex == resultSize);
2614 return resultArray;
2615 }
2616 }
2617
2618 for (TIntermNode *&argument : *aggregate->getSequence())
2619 {
2620 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2621 size_t argumentSize = argumentConstant->getType().getObjectSize();
2622 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2623 for (size_t i = 0u; i < argumentSize; ++i)
2624 {
2625 if (resultIndex >= resultSize)
2626 break;
2627 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2628 ++resultIndex;
2629 }
2630 }
2631 ASSERT(resultIndex == resultSize);
2632 return resultArray;
2633}
2634
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002635bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2636{
2637 switch (op)
2638 {
2639 case EOpAtan:
2640 case EOpPow:
2641 case EOpMod:
2642 case EOpMin:
2643 case EOpMax:
2644 case EOpClamp:
2645 case EOpMix:
2646 case EOpStep:
2647 case EOpSmoothStep:
2648 case EOpLdexp:
2649 case EOpMulMatrixComponentWise:
2650 case EOpOuterProduct:
2651 case EOpEqualComponentWise:
2652 case EOpNotEqualComponentWise:
2653 case EOpLessThanComponentWise:
2654 case EOpLessThanEqualComponentWise:
2655 case EOpGreaterThanComponentWise:
2656 case EOpGreaterThanEqualComponentWise:
2657 case EOpDistance:
2658 case EOpDot:
2659 case EOpCross:
2660 case EOpFaceforward:
2661 case EOpReflect:
2662 case EOpRefract:
2663 case EOpBitfieldExtract:
2664 case EOpBitfieldInsert:
2665 return true;
2666 default:
2667 return false;
2668 }
2669}
2670
Olli Etuaho1d122782015-11-06 15:35:17 +02002671// static
Olli Etuahof119a262016-08-19 15:54:22 +03002672TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2673 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302674{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002675 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002676 TIntermSequence *arguments = aggregate->getSequence();
2677 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2678 std::vector<const TConstantUnion *> unionArrays(argsCount);
2679 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002680 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302681 TBasicType basicType = EbtVoid;
2682 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002683 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302684 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002685 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2686 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302687
2688 if (i == 0)
2689 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002690 basicType = argConstant->getType().getBasicType();
2691 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302692 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002693 unionArrays[i] = argConstant->getUnionArrayPointer();
2694 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002695 if (objectSizes[i] > maxObjectSize)
2696 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302697 }
2698
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002699 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302700 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002701 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302702 if (objectSizes[i] != maxObjectSize)
2703 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2704 }
Arun Patole274f0702015-05-05 13:33:30 +05302705
Olli Etuahob43846e2015-06-02 18:18:57 +03002706 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002707
2708 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302709 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002710 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302711 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002712 ASSERT(basicType == EbtFloat);
2713 resultArray = new TConstantUnion[maxObjectSize];
2714 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302715 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002716 float y = unionArrays[0][i].getFConst();
2717 float x = unionArrays[1][i].getFConst();
2718 // Results are undefined if x and y are both 0.
2719 if (x == 0.0f && y == 0.0f)
2720 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2721 else
2722 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302723 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002724 break;
2725 }
Arun Patolebf790422015-05-18 17:53:04 +05302726
Olli Etuaho51182ab2017-01-22 00:12:29 +00002727 case EOpPow:
2728 {
2729 ASSERT(basicType == EbtFloat);
2730 resultArray = new TConstantUnion[maxObjectSize];
2731 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302732 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002733 float x = unionArrays[0][i].getFConst();
2734 float y = unionArrays[1][i].getFConst();
2735 // Results are undefined if x < 0.
2736 // Results are undefined if x = 0 and y <= 0.
2737 if (x < 0.0f)
2738 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2739 else if (x == 0.0f && y <= 0.0f)
2740 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2741 else
2742 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302743 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002744 break;
2745 }
Arun Patolebf790422015-05-18 17:53:04 +05302746
Olli Etuaho51182ab2017-01-22 00:12:29 +00002747 case EOpMod:
2748 {
2749 ASSERT(basicType == EbtFloat);
2750 resultArray = new TConstantUnion[maxObjectSize];
2751 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302752 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002753 float x = unionArrays[0][i].getFConst();
2754 float y = unionArrays[1][i].getFConst();
2755 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302756 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002757 break;
2758 }
Arun Patolebf790422015-05-18 17:53:04 +05302759
Olli Etuaho51182ab2017-01-22 00:12:29 +00002760 case EOpMin:
2761 {
2762 resultArray = new TConstantUnion[maxObjectSize];
2763 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302764 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002765 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302766 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002767 case EbtFloat:
2768 resultArray[i].setFConst(
2769 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2770 break;
2771 case EbtInt:
2772 resultArray[i].setIConst(
2773 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2774 break;
2775 case EbtUInt:
2776 resultArray[i].setUConst(
2777 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2778 break;
2779 default:
2780 UNREACHABLE();
2781 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302782 }
2783 }
2784 break;
Arun Patole274f0702015-05-05 13:33:30 +05302785 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002786
2787 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302788 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002789 resultArray = new TConstantUnion[maxObjectSize];
2790 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302791 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002792 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302793 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002794 case EbtFloat:
2795 resultArray[i].setFConst(
2796 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2797 break;
2798 case EbtInt:
2799 resultArray[i].setIConst(
2800 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2801 break;
2802 case EbtUInt:
2803 resultArray[i].setUConst(
2804 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2805 break;
2806 default:
2807 UNREACHABLE();
2808 break;
Arun Patole274f0702015-05-05 13:33:30 +05302809 }
2810 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002811 break;
Arun Patole274f0702015-05-05 13:33:30 +05302812 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002813
2814 case EOpStep:
2815 {
2816 ASSERT(basicType == EbtFloat);
2817 resultArray = new TConstantUnion[maxObjectSize];
2818 for (size_t i = 0; i < maxObjectSize; i++)
2819 resultArray[i].setFConst(
2820 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2821 break;
2822 }
2823
2824 case EOpLessThanComponentWise:
2825 {
2826 resultArray = new TConstantUnion[maxObjectSize];
2827 for (size_t i = 0; i < maxObjectSize; i++)
2828 {
2829 switch (basicType)
2830 {
2831 case EbtFloat:
2832 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2833 unionArrays[1][i].getFConst());
2834 break;
2835 case EbtInt:
2836 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2837 unionArrays[1][i].getIConst());
2838 break;
2839 case EbtUInt:
2840 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2841 unionArrays[1][i].getUConst());
2842 break;
2843 default:
2844 UNREACHABLE();
2845 break;
2846 }
2847 }
2848 break;
2849 }
2850
2851 case EOpLessThanEqualComponentWise:
2852 {
2853 resultArray = new TConstantUnion[maxObjectSize];
2854 for (size_t i = 0; i < maxObjectSize; i++)
2855 {
2856 switch (basicType)
2857 {
2858 case EbtFloat:
2859 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2860 unionArrays[1][i].getFConst());
2861 break;
2862 case EbtInt:
2863 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2864 unionArrays[1][i].getIConst());
2865 break;
2866 case EbtUInt:
2867 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2868 unionArrays[1][i].getUConst());
2869 break;
2870 default:
2871 UNREACHABLE();
2872 break;
2873 }
2874 }
2875 break;
2876 }
2877
2878 case EOpGreaterThanComponentWise:
2879 {
2880 resultArray = new TConstantUnion[maxObjectSize];
2881 for (size_t i = 0; i < maxObjectSize; i++)
2882 {
2883 switch (basicType)
2884 {
2885 case EbtFloat:
2886 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2887 unionArrays[1][i].getFConst());
2888 break;
2889 case EbtInt:
2890 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2891 unionArrays[1][i].getIConst());
2892 break;
2893 case EbtUInt:
2894 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2895 unionArrays[1][i].getUConst());
2896 break;
2897 default:
2898 UNREACHABLE();
2899 break;
2900 }
2901 }
2902 break;
2903 }
2904 case EOpGreaterThanEqualComponentWise:
2905 {
2906 resultArray = new TConstantUnion[maxObjectSize];
2907 for (size_t i = 0; i < maxObjectSize; i++)
2908 {
2909 switch (basicType)
2910 {
2911 case EbtFloat:
2912 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2913 unionArrays[1][i].getFConst());
2914 break;
2915 case EbtInt:
2916 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2917 unionArrays[1][i].getIConst());
2918 break;
2919 case EbtUInt:
2920 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2921 unionArrays[1][i].getUConst());
2922 break;
2923 default:
2924 UNREACHABLE();
2925 break;
2926 }
2927 }
2928 }
2929 break;
2930
2931 case EOpEqualComponentWise:
2932 {
2933 resultArray = new TConstantUnion[maxObjectSize];
2934 for (size_t i = 0; i < maxObjectSize; i++)
2935 {
2936 switch (basicType)
2937 {
2938 case EbtFloat:
2939 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2940 unionArrays[1][i].getFConst());
2941 break;
2942 case EbtInt:
2943 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2944 unionArrays[1][i].getIConst());
2945 break;
2946 case EbtUInt:
2947 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2948 unionArrays[1][i].getUConst());
2949 break;
2950 case EbtBool:
2951 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2952 unionArrays[1][i].getBConst());
2953 break;
2954 default:
2955 UNREACHABLE();
2956 break;
2957 }
2958 }
2959 break;
2960 }
2961
2962 case EOpNotEqualComponentWise:
2963 {
2964 resultArray = new TConstantUnion[maxObjectSize];
2965 for (size_t i = 0; i < maxObjectSize; i++)
2966 {
2967 switch (basicType)
2968 {
2969 case EbtFloat:
2970 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2971 unionArrays[1][i].getFConst());
2972 break;
2973 case EbtInt:
2974 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2975 unionArrays[1][i].getIConst());
2976 break;
2977 case EbtUInt:
2978 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2979 unionArrays[1][i].getUConst());
2980 break;
2981 case EbtBool:
2982 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2983 unionArrays[1][i].getBConst());
2984 break;
2985 default:
2986 UNREACHABLE();
2987 break;
2988 }
2989 }
2990 break;
2991 }
2992
2993 case EOpDistance:
2994 {
2995 ASSERT(basicType == EbtFloat);
2996 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2997 resultArray = new TConstantUnion();
2998 for (size_t i = 0; i < maxObjectSize; i++)
2999 {
3000 float x = unionArrays[0][i].getFConst();
3001 float y = unionArrays[1][i].getFConst();
3002 distanceArray[i].setFConst(x - y);
3003 }
3004 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3005 break;
3006 }
3007
3008 case EOpDot:
3009 ASSERT(basicType == EbtFloat);
3010 resultArray = new TConstantUnion();
3011 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3012 break;
3013
3014 case EOpCross:
3015 {
3016 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3017 resultArray = new TConstantUnion[maxObjectSize];
3018 float x0 = unionArrays[0][0].getFConst();
3019 float x1 = unionArrays[0][1].getFConst();
3020 float x2 = unionArrays[0][2].getFConst();
3021 float y0 = unionArrays[1][0].getFConst();
3022 float y1 = unionArrays[1][1].getFConst();
3023 float y2 = unionArrays[1][2].getFConst();
3024 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3025 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3026 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3027 break;
3028 }
3029
3030 case EOpReflect:
3031 {
3032 ASSERT(basicType == EbtFloat);
3033 // genType reflect (genType I, genType N) :
3034 // For the incident vector I and surface orientation N, returns the reflection
3035 // direction:
3036 // I - 2 * dot(N, I) * N.
3037 resultArray = new TConstantUnion[maxObjectSize];
3038 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3039 for (size_t i = 0; i < maxObjectSize; i++)
3040 {
3041 float result = unionArrays[0][i].getFConst() -
3042 2.0f * dotProduct * unionArrays[1][i].getFConst();
3043 resultArray[i].setFConst(result);
3044 }
3045 break;
3046 }
3047
3048 case EOpMulMatrixComponentWise:
3049 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003050 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3051 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003052 // Perform component-wise matrix multiplication.
3053 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003054 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003055 angle::Matrix<float> result =
3056 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3057 SetUnionArrayFromMatrix(result, resultArray);
3058 break;
3059 }
3060
3061 case EOpOuterProduct:
3062 {
3063 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003064 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3065 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003066 resultArray = new TConstantUnion[numRows * numCols];
3067 angle::Matrix<float> result =
3068 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3069 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3070 SetUnionArrayFromMatrix(result, resultArray);
3071 break;
3072 }
3073
3074 case EOpClamp:
3075 {
3076 resultArray = new TConstantUnion[maxObjectSize];
3077 for (size_t i = 0; i < maxObjectSize; i++)
3078 {
3079 switch (basicType)
3080 {
3081 case EbtFloat:
3082 {
3083 float x = unionArrays[0][i].getFConst();
3084 float min = unionArrays[1][i].getFConst();
3085 float max = unionArrays[2][i].getFConst();
3086 // Results are undefined if min > max.
3087 if (min > max)
3088 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3089 &resultArray[i]);
3090 else
3091 resultArray[i].setFConst(gl::clamp(x, min, max));
3092 break;
3093 }
3094
3095 case EbtInt:
3096 {
3097 int x = unionArrays[0][i].getIConst();
3098 int min = unionArrays[1][i].getIConst();
3099 int max = unionArrays[2][i].getIConst();
3100 // Results are undefined if min > max.
3101 if (min > max)
3102 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3103 &resultArray[i]);
3104 else
3105 resultArray[i].setIConst(gl::clamp(x, min, max));
3106 break;
3107 }
3108 case EbtUInt:
3109 {
3110 unsigned int x = unionArrays[0][i].getUConst();
3111 unsigned int min = unionArrays[1][i].getUConst();
3112 unsigned int max = unionArrays[2][i].getUConst();
3113 // Results are undefined if min > max.
3114 if (min > max)
3115 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3116 &resultArray[i]);
3117 else
3118 resultArray[i].setUConst(gl::clamp(x, min, max));
3119 break;
3120 }
3121 default:
3122 UNREACHABLE();
3123 break;
3124 }
3125 }
3126 break;
3127 }
3128
3129 case EOpMix:
3130 {
3131 ASSERT(basicType == EbtFloat);
3132 resultArray = new TConstantUnion[maxObjectSize];
3133 for (size_t i = 0; i < maxObjectSize; i++)
3134 {
3135 float x = unionArrays[0][i].getFConst();
3136 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003137 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003138 if (type == EbtFloat)
3139 {
3140 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3141 float a = unionArrays[2][i].getFConst();
3142 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3143 }
3144 else // 3rd parameter is EbtBool
3145 {
3146 ASSERT(type == EbtBool);
3147 // Selects which vector each returned component comes from.
3148 // For a component of a that is false, the corresponding component of x is
3149 // returned.
3150 // For a component of a that is true, the corresponding component of y is
3151 // returned.
3152 bool a = unionArrays[2][i].getBConst();
3153 resultArray[i].setFConst(a ? y : x);
3154 }
3155 }
3156 break;
3157 }
3158
3159 case EOpSmoothStep:
3160 {
3161 ASSERT(basicType == EbtFloat);
3162 resultArray = new TConstantUnion[maxObjectSize];
3163 for (size_t i = 0; i < maxObjectSize; i++)
3164 {
3165 float edge0 = unionArrays[0][i].getFConst();
3166 float edge1 = unionArrays[1][i].getFConst();
3167 float x = unionArrays[2][i].getFConst();
3168 // Results are undefined if edge0 >= edge1.
3169 if (edge0 >= edge1)
3170 {
3171 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3172 }
3173 else
3174 {
3175 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3176 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3177 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3178 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3179 }
3180 }
3181 break;
3182 }
3183
Olli Etuaho74da73f2017-02-01 15:37:48 +00003184 case EOpLdexp:
3185 {
3186 resultArray = new TConstantUnion[maxObjectSize];
3187 for (size_t i = 0; i < maxObjectSize; i++)
3188 {
3189 float x = unionArrays[0][i].getFConst();
3190 int exp = unionArrays[1][i].getIConst();
3191 if (exp > 128)
3192 {
3193 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3194 }
3195 else
3196 {
3197 resultArray[i].setFConst(gl::Ldexp(x, exp));
3198 }
3199 }
3200 break;
3201 }
3202
Jamie Madille72595b2017-06-06 15:12:26 -04003203 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003204 {
3205 ASSERT(basicType == EbtFloat);
3206 // genType faceforward(genType N, genType I, genType Nref) :
3207 // If dot(Nref, I) < 0 return N, otherwise return -N.
3208 resultArray = new TConstantUnion[maxObjectSize];
3209 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3210 for (size_t i = 0; i < maxObjectSize; i++)
3211 {
3212 if (dotProduct < 0)
3213 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3214 else
3215 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3216 }
3217 break;
3218 }
3219
3220 case EOpRefract:
3221 {
3222 ASSERT(basicType == EbtFloat);
3223 // genType refract(genType I, genType N, float eta) :
3224 // For the incident vector I and surface normal N, and the ratio of indices of
3225 // refraction eta,
3226 // return the refraction vector. The result is computed by
3227 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3228 // if (k < 0.0)
3229 // return genType(0.0)
3230 // else
3231 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3232 resultArray = new TConstantUnion[maxObjectSize];
3233 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3234 for (size_t i = 0; i < maxObjectSize; i++)
3235 {
3236 float eta = unionArrays[2][i].getFConst();
3237 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3238 if (k < 0.0f)
3239 resultArray[i].setFConst(0.0f);
3240 else
3241 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3242 (eta * dotProduct + sqrtf(k)) *
3243 unionArrays[1][i].getFConst());
3244 }
3245 break;
3246 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003247 case EOpBitfieldExtract:
3248 {
3249 resultArray = new TConstantUnion[maxObjectSize];
3250 for (size_t i = 0; i < maxObjectSize; ++i)
3251 {
3252 int offset = unionArrays[1][0].getIConst();
3253 int bits = unionArrays[2][0].getIConst();
3254 if (bits == 0)
3255 {
3256 if (aggregate->getBasicType() == EbtInt)
3257 {
3258 resultArray[i].setIConst(0);
3259 }
3260 else
3261 {
3262 ASSERT(aggregate->getBasicType() == EbtUInt);
3263 resultArray[i].setUConst(0);
3264 }
3265 }
3266 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3267 {
3268 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3269 &resultArray[i]);
3270 }
3271 else
3272 {
3273 // bits can be 32 here, so we need to avoid bit shift overflow.
3274 uint32_t maskMsb = 1u << (bits - 1);
3275 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3276 if (aggregate->getBasicType() == EbtInt)
3277 {
3278 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3279 uint32_t resultUnsigned = (value & mask) >> offset;
3280 if ((resultUnsigned & maskMsb) != 0)
3281 {
3282 // The most significant bits (from bits+1 to the most significant bit)
3283 // should be set to 1.
3284 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3285 resultUnsigned |= higherBitsMask;
3286 }
3287 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3288 }
3289 else
3290 {
3291 ASSERT(aggregate->getBasicType() == EbtUInt);
3292 uint32_t value = unionArrays[0][i].getUConst();
3293 resultArray[i].setUConst((value & mask) >> offset);
3294 }
3295 }
3296 }
3297 break;
3298 }
3299 case EOpBitfieldInsert:
3300 {
3301 resultArray = new TConstantUnion[maxObjectSize];
3302 for (size_t i = 0; i < maxObjectSize; ++i)
3303 {
3304 int offset = unionArrays[2][0].getIConst();
3305 int bits = unionArrays[3][0].getIConst();
3306 if (bits == 0)
3307 {
3308 if (aggregate->getBasicType() == EbtInt)
3309 {
3310 int32_t base = unionArrays[0][i].getIConst();
3311 resultArray[i].setIConst(base);
3312 }
3313 else
3314 {
3315 ASSERT(aggregate->getBasicType() == EbtUInt);
3316 uint32_t base = unionArrays[0][i].getUConst();
3317 resultArray[i].setUConst(base);
3318 }
3319 }
3320 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3321 {
3322 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3323 &resultArray[i]);
3324 }
3325 else
3326 {
3327 // bits can be 32 here, so we need to avoid bit shift overflow.
3328 uint32_t maskMsb = 1u << (bits - 1);
3329 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3330 uint32_t baseMask = ~insertMask;
3331 if (aggregate->getBasicType() == EbtInt)
3332 {
3333 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3334 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3335 uint32_t resultUnsigned =
3336 (base & baseMask) | ((insert << offset) & insertMask);
3337 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3338 }
3339 else
3340 {
3341 ASSERT(aggregate->getBasicType() == EbtUInt);
3342 uint32_t base = unionArrays[0][i].getUConst();
3343 uint32_t insert = unionArrays[1][i].getUConst();
3344 resultArray[i].setUConst((base & baseMask) |
3345 ((insert << offset) & insertMask));
3346 }
3347 }
3348 }
3349 break;
3350 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003351
3352 default:
3353 UNREACHABLE();
3354 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303355 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003356 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303357}
3358
Jamie Madill45bcc782016-11-07 13:58:48 -05003359} // namespace sh