blob: 9bbd4e2a91af9041058f1b1dc5cd098a2851c572 [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 Etuaho2768bc82017-12-12 11:51:48 +020098TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray, const TIntermTyped *originalNode)
Olli Etuahob43846e2015-06-02 18:18:57 +030099{
Olli Etuaho2768bc82017-12-12 11:51:48 +0200100 ASSERT(constArray != nullptr);
101 // Note that we inherit whatever qualifier the folded node had. Nodes may be constant folded
102 // without being qualified as constant.
Olli Etuahob43846e2015-06-02 18:18:57 +0300103 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuahob43846e2015-06-02 18:18:57 +0300104 folded->setLine(originalNode->getLine());
105 return folded;
106}
107
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200108angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
109 const unsigned int &rows,
110 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530111{
112 std::vector<float> elements;
113 for (size_t i = 0; i < rows * cols; i++)
114 elements.push_back(paramArray[i].getFConst());
115 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300116 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
117 // so that the created matrix will have the expected dimensions after the transpose.
118 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530119}
120
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200121angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530122{
123 std::vector<float> elements;
124 for (size_t i = 0; i < size * size; i++)
125 elements.push_back(paramArray[i].getFConst());
126 // Transpose is used since the Matrix constructor expects arguments in row-major order,
127 // whereas the paramArray is in column-major order.
128 return angle::Matrix<float>(elements, size).transpose();
129}
130
131void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
132{
133 // Transpose is used since the input Matrix is in row-major order,
134 // whereas the actual result should be in column-major order.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500135 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530136 std::vector<float> resultElements = result.elements();
137 for (size_t i = 0; i < resultElements.size(); i++)
138 resultArray[i].setFConst(resultElements[i]);
139}
140
Olli Etuaho765924f2018-01-04 12:48:36 +0200141bool CanFoldAggregateBuiltInOp(TOperator op)
142{
143 switch (op)
144 {
145 case EOpAtan:
146 case EOpPow:
147 case EOpMod:
148 case EOpMin:
149 case EOpMax:
150 case EOpClamp:
151 case EOpMix:
152 case EOpStep:
153 case EOpSmoothStep:
154 case EOpLdexp:
155 case EOpMulMatrixComponentWise:
156 case EOpOuterProduct:
157 case EOpEqualComponentWise:
158 case EOpNotEqualComponentWise:
159 case EOpLessThanComponentWise:
160 case EOpLessThanEqualComponentWise:
161 case EOpGreaterThanComponentWise:
162 case EOpGreaterThanEqualComponentWise:
163 case EOpDistance:
164 case EOpDot:
165 case EOpCross:
166 case EOpFaceforward:
167 case EOpReflect:
168 case EOpRefract:
169 case EOpBitfieldExtract:
170 case EOpBitfieldInsert:
171 return true;
172 default:
173 return false;
174 }
175}
176
Jamie Madillb1a85f42014-08-19 15:23:24 -0400177} // namespace anonymous
178
Jamie Madillb1a85f42014-08-19 15:23:24 -0400179////////////////////////////////////////////////////////////////
180//
181// Member functions of the nodes used for building the tree.
182//
183////////////////////////////////////////////////////////////////
184
Olli Etuahod2a67b92014-10-21 16:42:57 +0300185void TIntermTyped::setTypePreservePrecision(const TType &t)
186{
187 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500188 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300189 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
190 mType.setPrecision(precision);
191}
192
Jamie Madillb1a85f42014-08-19 15:23:24 -0400193#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500194 if (node == original) \
195 { \
196 node = static_cast<type *>(replacement); \
197 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400198 }
199
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500200bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400201{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300202 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400203 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
204 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
205 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100206 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400207 return false;
208}
209
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500210bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400211{
212 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
213 return false;
214}
215
Olli Etuahob6fa0432016-09-28 16:28:05 +0100216bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
217{
218 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
219 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
220 return false;
221}
222
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500223bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400224{
225 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
226 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
227 return false;
228}
229
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500230bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400231{
Olli Etuahoa2234302016-08-31 12:05:39 +0300232 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400233 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
234 return false;
235}
236
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000237bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
238{
239 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
240 return false;
241}
242
Olli Etuaho336b1472016-10-05 16:37:55 +0100243bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
244{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000245 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100246 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
247 return false;
248}
249
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500250bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400251{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100252 return replaceChildNodeInternal(original, replacement);
253}
254
255bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
256{
257 return replaceChildNodeInternal(original, replacement);
258}
259
Olli Etuaho16c745a2017-01-16 17:02:27 +0000260bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
261{
262 return replaceChildNodeInternal(original, replacement);
263}
264
Olli Etuaho13389b62016-10-16 11:48:18 +0100265bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
266{
267 return replaceChildNodeInternal(original, replacement);
268}
269
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100270bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
271{
272 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400273 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100274 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400275 }
276 return false;
277}
278
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100279bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
280 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300281{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100282 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300283 {
284 if (*it == original)
285 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100286 it = getSequence()->erase(it);
287 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300288 return true;
289 }
290 }
291 return false;
292}
293
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100294bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
295 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300296{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100297 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300298 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300299 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300300 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100301 auto it = getSequence()->begin() + position;
302 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300303 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300304}
305
Olli Etuaho195be942017-12-04 23:40:14 +0200306TIntermSymbol::TIntermSymbol(const TVariable *variable)
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200307 : TIntermTyped(variable->getType()), mVariable(variable)
Olli Etuaho195be942017-12-04 23:40:14 +0200308{
Olli Etuaho195be942017-12-04 23:40:14 +0200309}
310
Olli Etuahob6af22b2017-12-15 14:05:44 +0200311const TSymbolUniqueId &TIntermSymbol::uniqueId() const
312{
313 return mVariable->uniqueId();
314}
315
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200316const TString &TIntermSymbol::getName() const
317{
318 return mVariable->name();
319}
320
Olli Etuahofe486322017-03-21 09:30:54 +0000321TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
322 TIntermSequence *arguments)
323{
Olli Etuaho0c371002017-12-13 17:00:25 +0400324 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000325}
326
Olli Etuaho0c371002017-12-13 17:00:25 +0400327TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
328 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000329{
Olli Etuaho0c371002017-12-13 17:00:25 +0400330 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000331}
332
333TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
334 TIntermSequence *arguments)
335{
336 TIntermAggregate *callNode =
Olli Etuaho0c371002017-12-13 17:00:25 +0400337 new TIntermAggregate(&func, func.getReturnType(), EOpCallBuiltInFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000338 // Note that name needs to be set before texture function type is determined.
339 callNode->setBuiltInFunctionPrecision();
340 return callNode;
341}
342
343TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000344 TIntermSequence *arguments)
345{
Olli Etuaho0c371002017-12-13 17:00:25 +0400346 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000347}
348
349TIntermAggregate *TIntermAggregate::Create(const TType &type,
350 TOperator op,
351 TIntermSequence *arguments)
352{
Olli Etuahofe486322017-03-21 09:30:54 +0000353 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400354 ASSERT(op != EOpCallInternalRawFunction); // Should use CreateRawFunctionCall
Olli Etuahofe486322017-03-21 09:30:54 +0000355 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400356 ASSERT(op != EOpConstruct); // Should use CreateConstructor
357 return new TIntermAggregate(nullptr, type, op, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000358}
359
Olli Etuaho0c371002017-12-13 17:00:25 +0400360TIntermAggregate::TIntermAggregate(const TFunction *func,
361 const TType &type,
362 TOperator op,
363 TIntermSequence *arguments)
364 : TIntermOperator(op),
365 mUseEmulatedFunction(false),
366 mGotPrecisionFromChildren(false),
367 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800368{
369 if (arguments != nullptr)
370 {
371 mArguments.swap(*arguments);
372 }
Olli Etuaho1bb85282017-12-14 13:39:53 +0200373 ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800374 setTypePrecisionAndQualifier(type);
375}
376
377void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
378{
379 setType(type);
380 mType.setQualifier(EvqTemporary);
381 if (!isFunctionCall())
382 {
383 if (isConstructor())
384 {
385 // Structs should not be precision qualified, the individual members may be.
386 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300387 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800388 {
389 setPrecisionFromChildren();
390 }
391 }
392 else
393 {
394 setPrecisionForBuiltInOp();
395 }
396 if (areChildrenConstQualified())
397 {
398 mType.setQualifier(EvqConst);
399 }
400 }
401}
402
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200403bool TIntermAggregate::areChildrenConstQualified()
404{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800405 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200406 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800407 TIntermTyped *typedArg = arg->getAsTyped();
408 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200409 {
410 return false;
411 }
412 }
413 return true;
414}
415
Olli Etuahod2a67b92014-10-21 16:42:57 +0300416void TIntermAggregate::setPrecisionFromChildren()
417{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300418 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300419 if (getBasicType() == EbtBool)
420 {
421 mType.setPrecision(EbpUndefined);
422 return;
423 }
424
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500425 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800426 TIntermSequence::iterator childIter = mArguments.begin();
427 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300428 {
429 TIntermTyped *typed = (*childIter)->getAsTyped();
430 if (typed)
431 precision = GetHigherPrecision(typed->getPrecision(), precision);
432 ++childIter;
433 }
434 mType.setPrecision(precision);
435}
436
Olli Etuaho9250cb22017-01-21 10:51:27 +0000437void TIntermAggregate::setPrecisionForBuiltInOp()
438{
439 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800440 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000441 if (!setPrecisionForSpecialBuiltInOp())
442 {
443 setPrecisionFromChildren();
444 }
445}
446
447bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
448{
449 switch (mOp)
450 {
451 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800452 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
453 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000454 return true;
455 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800456 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
457 mArguments[1]->getAsTyped()->getPrecision()));
458 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000459 return true;
460 case EOpUaddCarry:
461 case EOpUsubBorrow:
462 mType.setPrecision(EbpHigh);
463 return true;
464 default:
465 return false;
466 }
467}
468
Olli Etuahod2a67b92014-10-21 16:42:57 +0300469void TIntermAggregate::setBuiltInFunctionPrecision()
470{
471 // All built-ins returning bool should be handled as ops, not functions.
472 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800473 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300474
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800475 TPrecision precision = EbpUndefined;
476 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300477 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800478 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300479 // ESSL spec section 8: texture functions get their precision from the sampler.
480 if (typed && IsSampler(typed->getBasicType()))
481 {
482 precision = typed->getPrecision();
483 break;
484 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300485 }
486 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
487 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobed35d72017-12-20 16:36:26 +0200488 if (mFunction->name().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300489 mType.setPrecision(EbpHigh);
490 else
491 mType.setPrecision(precision);
492}
493
Olli Etuahof2209f72017-04-01 12:45:55 +0300494TString TIntermAggregate::getSymbolTableMangledName() const
495{
496 ASSERT(!isConstructor());
497 switch (mOp)
498 {
499 case EOpCallInternalRawFunction:
500 case EOpCallBuiltInFunction:
501 case EOpCallFunctionInAST:
Olli Etuahobed35d72017-12-20 16:36:26 +0200502 return TFunction::GetMangledNameFromCall(mFunction->name(), mArguments);
Olli Etuahof2209f72017-04-01 12:45:55 +0300503 default:
504 TString opString = GetOperatorString(mOp);
505 return TFunction::GetMangledNameFromCall(opString, mArguments);
506 }
507}
508
Olli Etuaho0c371002017-12-13 17:00:25 +0400509const char *TIntermAggregate::functionName() const
510{
511 ASSERT(!isConstructor());
512 switch (mOp)
513 {
514 case EOpCallInternalRawFunction:
515 case EOpCallBuiltInFunction:
516 case EOpCallFunctionInAST:
Olli Etuahobed35d72017-12-20 16:36:26 +0200517 return mFunction->name().c_str();
Olli Etuaho0c371002017-12-13 17:00:25 +0400518 default:
519 return GetOperatorString(mOp);
520 }
521}
522
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300523bool TIntermAggregate::hasSideEffects() const
524{
Olli Etuaho0c371002017-12-13 17:00:25 +0400525 if (isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300526 {
527 for (TIntermNode *arg : mArguments)
528 {
529 if (arg->getAsTyped()->hasSideEffects())
530 {
531 return true;
532 }
533 }
534 return false;
535 }
536 // Conservatively assume most aggregate operators have side-effects
537 return true;
538}
539
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100540void TIntermBlock::appendStatement(TIntermNode *statement)
541{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300542 // Declaration nodes with no children can appear if it was an empty declaration or if all the
543 // declarators just added constants to the symbol table instead of generating code. We still
544 // need to add the declaration to the AST in that case because it might be relevant to the
545 // validity of switch/case.
546 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100547 {
548 mStatements.push_back(statement);
549 }
550}
551
Olli Etuaho16c745a2017-01-16 17:02:27 +0000552void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
553{
554 ASSERT(parameter != nullptr);
555 mParameters.push_back(parameter);
556}
557
Olli Etuaho13389b62016-10-16 11:48:18 +0100558void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
559{
560 ASSERT(declarator != nullptr);
561 ASSERT(declarator->getAsSymbolNode() != nullptr ||
562 (declarator->getAsBinaryNode() != nullptr &&
563 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
564 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300565 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100566 mDeclarators.push_back(declarator);
567}
568
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300569bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
570{
571 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
572 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
573 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
574 return false;
575}
576
Olli Etuaho57961272016-09-14 13:57:46 +0300577bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400578{
579 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100580 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
581 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400582 return false;
583}
584
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500585bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200586{
587 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100588 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300589 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200590 return false;
591}
592
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500593bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200594{
595 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
596 return false;
597}
598
Olli Etuahod7a25242015-08-18 13:49:45 +0300599TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
600{
601 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
602 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
603 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
604 mLine = node.mLine;
605}
606
Olli Etuahod4f4c112016-04-15 15:11:24 +0300607bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
608{
609 TIntermAggregate *constructor = getAsAggregate();
610 if (!constructor || !constructor->isConstructor())
611 {
612 return false;
613 }
614 for (TIntermNode *&node : *constructor->getSequence())
615 {
616 if (!node->getAsConstantUnion())
617 return false;
618 }
619 return true;
620}
621
Olli Etuahod7a25242015-08-18 13:49:45 +0300622TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
623{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200624 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300625}
626
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200627TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
628 : TIntermTyped(function->getReturnType()), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100629{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200630 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100631}
632
Olli Etuahod7a25242015-08-18 13:49:45 +0300633TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
634 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300635 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100636 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400637 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300638{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800639 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300640 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800641 TIntermTyped *typedArg = arg->getAsTyped();
642 ASSERT(typedArg != nullptr);
643 TIntermTyped *argCopy = typedArg->deepCopy();
644 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300645 }
646}
647
Olli Etuahofe486322017-03-21 09:30:54 +0000648TIntermAggregate *TIntermAggregate::shallowCopy() const
649{
650 TIntermSequence *copySeq = new TIntermSequence();
651 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400652 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000653 copyNode->setLine(mLine);
654 return copyNode;
655}
656
Olli Etuahob6fa0432016-09-28 16:28:05 +0100657TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
658{
659 TIntermTyped *operandCopy = node.mOperand->deepCopy();
660 ASSERT(operandCopy != nullptr);
661 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000662 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100663}
664
Olli Etuahod7a25242015-08-18 13:49:45 +0300665TIntermBinary::TIntermBinary(const TIntermBinary &node)
666 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
667{
668 TIntermTyped *leftCopy = node.mLeft->deepCopy();
669 TIntermTyped *rightCopy = node.mRight->deepCopy();
670 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
671 mLeft = leftCopy;
672 mRight = rightCopy;
673}
674
675TIntermUnary::TIntermUnary(const TIntermUnary &node)
676 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
677{
678 TIntermTyped *operandCopy = node.mOperand->deepCopy();
679 ASSERT(operandCopy != nullptr);
680 mOperand = operandCopy;
681}
682
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300683TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300684{
Olli Etuahod7a25242015-08-18 13:49:45 +0300685 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300686 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
687 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300688 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300689 mCondition = conditionCopy;
690 mTrueExpression = trueCopy;
691 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300692}
693
Jamie Madillb1a85f42014-08-19 15:23:24 -0400694bool TIntermOperator::isAssignment() const
695{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300696 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400697}
698
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300699bool TIntermOperator::isMultiplication() const
700{
701 switch (mOp)
702 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500703 case EOpMul:
704 case EOpMatrixTimesMatrix:
705 case EOpMatrixTimesVector:
706 case EOpMatrixTimesScalar:
707 case EOpVectorTimesMatrix:
708 case EOpVectorTimesScalar:
709 return true;
710 default:
711 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300712 }
713}
714
Jamie Madillb1a85f42014-08-19 15:23:24 -0400715bool TIntermOperator::isConstructor() const
716{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300717 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400718}
719
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800720bool TIntermOperator::isFunctionCall() const
721{
722 switch (mOp)
723 {
724 case EOpCallFunctionInAST:
725 case EOpCallBuiltInFunction:
726 case EOpCallInternalRawFunction:
727 return true;
728 default:
729 return false;
730 }
731}
732
Olli Etuaho1dded802016-08-18 18:13:13 +0300733TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
734{
735 if (left.isMatrix())
736 {
737 if (right.isMatrix())
738 {
739 return EOpMatrixTimesMatrix;
740 }
741 else
742 {
743 if (right.isVector())
744 {
745 return EOpMatrixTimesVector;
746 }
747 else
748 {
749 return EOpMatrixTimesScalar;
750 }
751 }
752 }
753 else
754 {
755 if (right.isMatrix())
756 {
757 if (left.isVector())
758 {
759 return EOpVectorTimesMatrix;
760 }
761 else
762 {
763 return EOpMatrixTimesScalar;
764 }
765 }
766 else
767 {
768 // Neither operand is a matrix.
769 if (left.isVector() == right.isVector())
770 {
771 // Leave as component product.
772 return EOpMul;
773 }
774 else
775 {
776 return EOpVectorTimesScalar;
777 }
778 }
779 }
780}
781
782TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
783{
784 if (left.isMatrix())
785 {
786 if (right.isMatrix())
787 {
788 return EOpMatrixTimesMatrixAssign;
789 }
790 else
791 {
792 // right should be scalar, but this may not be validated yet.
793 return EOpMatrixTimesScalarAssign;
794 }
795 }
796 else
797 {
798 if (right.isMatrix())
799 {
800 // Left should be a vector, but this may not be validated yet.
801 return EOpVectorTimesMatrixAssign;
802 }
803 else
804 {
805 // Neither operand is a matrix.
806 if (left.isVector() == right.isVector())
807 {
808 // Leave as component product.
809 return EOpMulAssign;
810 }
811 else
812 {
813 // left should be vector and right should be scalar, but this may not be validated
814 // yet.
815 return EOpVectorTimesScalarAssign;
816 }
817 }
818 }
819}
820
Jamie Madillb1a85f42014-08-19 15:23:24 -0400821//
822// Make sure the type of a unary operator is appropriate for its
823// combination of operation and operand type.
824//
Olli Etuahoa2234302016-08-31 12:05:39 +0300825void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400826{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300827 if (mOp == EOpArrayLength)
828 {
829 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
830 setType(TType(EbtInt, EbpUndefined, EvqConst));
831 return;
832 }
833
Olli Etuahoa2234302016-08-31 12:05:39 +0300834 TQualifier resultQualifier = EvqTemporary;
835 if (mOperand->getQualifier() == EvqConst)
836 resultQualifier = EvqConst;
837
838 unsigned char operandPrimarySize =
839 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400840 switch (mOp)
841 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300842 case EOpFloatBitsToInt:
843 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
844 break;
845 case EOpFloatBitsToUint:
846 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
847 break;
848 case EOpIntBitsToFloat:
849 case EOpUintBitsToFloat:
850 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
851 break;
852 case EOpPackSnorm2x16:
853 case EOpPackUnorm2x16:
854 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800855 case EOpPackUnorm4x8:
856 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300857 setType(TType(EbtUInt, EbpHigh, resultQualifier));
858 break;
859 case EOpUnpackSnorm2x16:
860 case EOpUnpackUnorm2x16:
861 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
862 break;
863 case EOpUnpackHalf2x16:
864 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
865 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800866 case EOpUnpackUnorm4x8:
867 case EOpUnpackSnorm4x8:
868 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
869 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300870 case EOpAny:
871 case EOpAll:
872 setType(TType(EbtBool, EbpUndefined, resultQualifier));
873 break;
874 case EOpLength:
875 case EOpDeterminant:
876 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
877 break;
878 case EOpTranspose:
879 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
880 static_cast<unsigned char>(mOperand->getType().getRows()),
881 static_cast<unsigned char>(mOperand->getType().getCols())));
882 break;
883 case EOpIsInf:
884 case EOpIsNan:
885 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
886 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000887 case EOpBitfieldReverse:
888 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
889 break;
890 case EOpBitCount:
891 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
892 break;
893 case EOpFindLSB:
894 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
895 break;
896 case EOpFindMSB:
897 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
898 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300899 default:
900 setType(mOperand->getType());
901 mType.setQualifier(resultQualifier);
902 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400903 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300904}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400905
Olli Etuahob6fa0432016-09-28 16:28:05 +0100906TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
907 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
908 mOperand(operand),
909 mSwizzleOffsets(swizzleOffsets)
910{
911 ASSERT(mSwizzleOffsets.size() <= 4);
912 promote();
913}
914
Olli Etuahoa2234302016-08-31 12:05:39 +0300915TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
916 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
917{
918 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400919}
920
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300921TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
922 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
923{
924 promote();
925}
926
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000927TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
928 : TIntermNode(), mSymbol(symbol)
929{
930 ASSERT(symbol);
931 setLine(line);
932}
933
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300934TIntermTernary::TIntermTernary(TIntermTyped *cond,
935 TIntermTyped *trueExpression,
936 TIntermTyped *falseExpression)
937 : TIntermTyped(trueExpression->getType()),
938 mCondition(cond),
939 mTrueExpression(trueExpression),
940 mFalseExpression(falseExpression)
941{
942 getTypePointer()->setQualifier(
943 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
944}
945
Olli Etuaho81629262017-04-19 11:56:01 +0300946TIntermLoop::TIntermLoop(TLoopType type,
947 TIntermNode *init,
948 TIntermTyped *cond,
949 TIntermTyped *expr,
950 TIntermBlock *body)
951 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
952{
953 // Declaration nodes with no children can appear if all the declarators just added constants to
954 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
955 if (mInit && mInit->getAsDeclarationNode() &&
956 mInit->getAsDeclarationNode()->getSequence()->empty())
957 {
958 mInit = nullptr;
959 }
960}
961
Olli Etuaho923ecef2017-10-11 12:01:38 +0300962TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
963 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
964{
965 // Prune empty false blocks so that there won't be unnecessary operations done on it.
966 if (mFalseBlock && mFalseBlock->getSequence()->empty())
967 {
968 mFalseBlock = nullptr;
969 }
970}
971
972TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
973 : TIntermNode(), mInit(init), mStatementList(statementList)
974{
975 ASSERT(mStatementList);
976}
977
978void TIntermSwitch::setStatementList(TIntermBlock *statementList)
979{
980 ASSERT(statementList);
981 mStatementList = statementList;
982}
983
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300984// static
985TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
986 TIntermTyped *trueExpression,
987 TIntermTyped *falseExpression)
988{
989 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
990 falseExpression->getQualifier() == EvqConst)
991 {
992 return EvqConst;
993 }
994 return EvqTemporary;
995}
996
Olli Etuaho765924f2018-01-04 12:48:36 +0200997TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
Olli Etuahoeb7f90f2017-07-07 17:25:23 +0300998{
999 if (mCondition->getAsConstantUnion())
1000 {
1001 if (mCondition->getAsConstantUnion()->getBConst(0))
1002 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001003 return mTrueExpression;
1004 }
1005 else
1006 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001007 return mFalseExpression;
1008 }
1009 }
1010 return this;
1011}
1012
Olli Etuahob6fa0432016-09-28 16:28:05 +01001013void TIntermSwizzle::promote()
1014{
1015 TQualifier resultQualifier = EvqTemporary;
1016 if (mOperand->getQualifier() == EvqConst)
1017 resultQualifier = EvqConst;
1018
1019 auto numFields = mSwizzleOffsets.size();
1020 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1021 static_cast<unsigned char>(numFields)));
1022}
1023
1024bool TIntermSwizzle::hasDuplicateOffsets() const
1025{
1026 int offsetCount[4] = {0u, 0u, 0u, 0u};
1027 for (const auto offset : mSwizzleOffsets)
1028 {
1029 offsetCount[offset]++;
1030 if (offsetCount[offset] > 1)
1031 {
1032 return true;
1033 }
1034 }
1035 return false;
1036}
1037
Olli Etuaho09b04a22016-12-15 13:30:26 +00001038bool TIntermSwizzle::offsetsMatch(int offset) const
1039{
1040 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1041}
1042
Olli Etuahob6fa0432016-09-28 16:28:05 +01001043void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1044{
1045 for (const int offset : mSwizzleOffsets)
1046 {
1047 switch (offset)
1048 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001049 case 0:
1050 *out << "x";
1051 break;
1052 case 1:
1053 *out << "y";
1054 break;
1055 case 2:
1056 *out << "z";
1057 break;
1058 case 3:
1059 *out << "w";
1060 break;
1061 default:
1062 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001063 }
1064 }
1065}
1066
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001067TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1068 const TIntermTyped *left,
1069 const TIntermTyped *right)
1070{
1071 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1072 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1073 right->getQualifier() != EvqConst)
1074 {
1075 return EvqTemporary;
1076 }
1077 return EvqConst;
1078}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001079
1080// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001081void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001082{
Olli Etuaho1dded802016-08-18 18:13:13 +03001083 ASSERT(!isMultiplication() ||
1084 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1085
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001086 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1087 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001088 if (mOp == EOpComma)
1089 {
1090 setType(mRight->getType());
1091 return;
1092 }
1093
Jamie Madillb1a85f42014-08-19 15:23:24 -04001094 // Base assumption: just make the type the same as the left
1095 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001096 setType(mLeft->getType());
1097
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001098 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001099 // Binary operations results in temporary variables unless both
1100 // operands are const.
1101 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1102 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001103 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001104 getTypePointer()->setQualifier(EvqTemporary);
1105 }
1106
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001107 // Handle indexing ops.
1108 switch (mOp)
1109 {
1110 case EOpIndexDirect:
1111 case EOpIndexIndirect:
1112 if (mLeft->isArray())
1113 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001114 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001115 }
1116 else if (mLeft->isMatrix())
1117 {
1118 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1119 static_cast<unsigned char>(mLeft->getRows())));
1120 }
1121 else if (mLeft->isVector())
1122 {
1123 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1124 }
1125 else
1126 {
1127 UNREACHABLE();
1128 }
1129 return;
1130 case EOpIndexDirectStruct:
1131 {
1132 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1133 const int i = mRight->getAsConstantUnion()->getIConst(0);
1134 setType(*fields[i]->type());
1135 getTypePointer()->setQualifier(resultQualifier);
1136 return;
1137 }
1138 case EOpIndexDirectInterfaceBlock:
1139 {
1140 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1141 const int i = mRight->getAsConstantUnion()->getIConst(0);
1142 setType(*fields[i]->type());
1143 getTypePointer()->setQualifier(resultQualifier);
1144 return;
1145 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001146 default:
1147 break;
1148 }
1149
1150 ASSERT(mLeft->isArray() == mRight->isArray());
1151
1152 // The result gets promoted to the highest precision.
1153 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1154 getTypePointer()->setPrecision(higherPrecision);
1155
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001156 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001157
1158 //
1159 // All scalars or structs. Code after this test assumes this case is removed!
1160 //
1161 if (nominalSize == 1)
1162 {
1163 switch (mOp)
1164 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001165 //
1166 // Promote to conditional
1167 //
1168 case EOpEqual:
1169 case EOpNotEqual:
1170 case EOpLessThan:
1171 case EOpGreaterThan:
1172 case EOpLessThanEqual:
1173 case EOpGreaterThanEqual:
1174 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1175 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001176
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001177 //
1178 // And and Or operate on conditionals
1179 //
1180 case EOpLogicalAnd:
1181 case EOpLogicalXor:
1182 case EOpLogicalOr:
1183 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1184 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1185 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001186
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001187 default:
1188 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001189 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001190 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001191 }
1192
1193 // If we reach here, at least one of the operands is vector or matrix.
1194 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001195 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001196
Jamie Madillb1a85f42014-08-19 15:23:24 -04001197 switch (mOp)
1198 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001199 case EOpMul:
1200 break;
1201 case EOpMatrixTimesScalar:
1202 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001203 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001204 setType(TType(basicType, higherPrecision, resultQualifier,
1205 static_cast<unsigned char>(mRight->getCols()),
1206 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001207 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001208 break;
1209 case EOpMatrixTimesVector:
1210 setType(TType(basicType, higherPrecision, resultQualifier,
1211 static_cast<unsigned char>(mLeft->getRows()), 1));
1212 break;
1213 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001214 setType(TType(basicType, higherPrecision, resultQualifier,
1215 static_cast<unsigned char>(mRight->getCols()),
1216 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001217 break;
1218 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001219 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001220 static_cast<unsigned char>(nominalSize), 1));
1221 break;
1222 case EOpVectorTimesMatrix:
1223 setType(TType(basicType, higherPrecision, resultQualifier,
1224 static_cast<unsigned char>(mRight->getCols()), 1));
1225 break;
1226 case EOpMulAssign:
1227 case EOpVectorTimesScalarAssign:
1228 case EOpVectorTimesMatrixAssign:
1229 case EOpMatrixTimesScalarAssign:
1230 case EOpMatrixTimesMatrixAssign:
1231 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1232 break;
1233 case EOpAssign:
1234 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001235 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1236 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1237 break;
1238 case EOpAdd:
1239 case EOpSub:
1240 case EOpDiv:
1241 case EOpIMod:
1242 case EOpBitShiftLeft:
1243 case EOpBitShiftRight:
1244 case EOpBitwiseAnd:
1245 case EOpBitwiseXor:
1246 case EOpBitwiseOr:
1247 case EOpAddAssign:
1248 case EOpSubAssign:
1249 case EOpDivAssign:
1250 case EOpIModAssign:
1251 case EOpBitShiftLeftAssign:
1252 case EOpBitShiftRightAssign:
1253 case EOpBitwiseAndAssign:
1254 case EOpBitwiseXorAssign:
1255 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001256 {
1257 const int secondarySize =
1258 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1259 setType(TType(basicType, higherPrecision, resultQualifier,
1260 static_cast<unsigned char>(nominalSize),
1261 static_cast<unsigned char>(secondarySize)));
1262 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001263 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001264 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001265 case EOpEqual:
1266 case EOpNotEqual:
1267 case EOpLessThan:
1268 case EOpGreaterThan:
1269 case EOpLessThanEqual:
1270 case EOpGreaterThanEqual:
1271 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1272 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001273 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001274 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001275
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001276 case EOpIndexDirect:
1277 case EOpIndexIndirect:
1278 case EOpIndexDirectInterfaceBlock:
1279 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001280 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001281 UNREACHABLE();
1282 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001283 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001284 UNREACHABLE();
1285 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001286 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001287}
1288
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001289const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001290{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001291 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001292 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001293 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001294 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001295 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001296 size_t arrayElementSize = arrayElementType.getObjectSize();
1297 return &mUnionArrayPointer[arrayElementSize * index];
1298 }
1299 else if (isMatrix())
1300 {
1301 ASSERT(index < getType().getCols());
1302 int size = getType().getRows();
1303 return &mUnionArrayPointer[size * index];
1304 }
1305 else if (isVector())
1306 {
1307 ASSERT(index < getType().getNominalSize());
1308 return &mUnionArrayPointer[index];
1309 }
1310 else
1311 {
1312 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001313 return nullptr;
1314 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001315}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001316
Olli Etuaho765924f2018-01-04 12:48:36 +02001317TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001318{
1319 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1320 if (operandConstant == nullptr)
1321 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001322 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001323 }
1324
1325 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1326 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1327 {
1328 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1329 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001330 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001331}
1332
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001333TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1334{
1335 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1336 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1337 switch (mOp)
1338 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001339 case EOpComma:
1340 {
1341 if (mLeft->hasSideEffects())
1342 {
1343 return this;
1344 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001345 return mRight;
1346 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001347 case EOpIndexDirect:
1348 {
1349 if (leftConstant == nullptr || rightConstant == nullptr)
1350 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001351 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001352 }
1353 int index = rightConstant->getIConst(0);
1354
1355 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001356 if (!constArray)
1357 {
1358 return this;
1359 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001360 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001361 }
1362 case EOpIndexDirectStruct:
1363 {
1364 if (leftConstant == nullptr || rightConstant == nullptr)
1365 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001366 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001367 }
1368 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1369 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1370
1371 size_t previousFieldsSize = 0;
1372 for (size_t i = 0; i < index; ++i)
1373 {
1374 previousFieldsSize += fields[i]->type()->getObjectSize();
1375 }
1376
1377 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
Olli Etuaho2768bc82017-12-12 11:51:48 +02001378 return CreateFoldedNode(constArray + previousFieldsSize, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001379 }
1380 case EOpIndexIndirect:
1381 case EOpIndexDirectInterfaceBlock:
1382 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001383 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001384 default:
1385 {
1386 if (leftConstant == nullptr || rightConstant == nullptr)
1387 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001388 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001389 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001390 TConstantUnion *constArray =
1391 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001392 if (!constArray)
1393 {
1394 return this;
1395 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001396 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001397 }
1398 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001399}
1400
Olli Etuahof119a262016-08-19 15:54:22 +03001401TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001402{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301403 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001404
1405 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301406 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001407 // The size of runtime-sized arrays may only be determined at runtime.
1408 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001409 {
1410 return this;
1411 }
1412 constArray = new TConstantUnion[1];
1413 constArray->setIConst(mOperand->getOutermostArraySize());
1414 }
1415 else
1416 {
1417 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1418 if (operandConstant == nullptr)
1419 {
1420 return this;
1421 }
1422
1423 switch (mOp)
1424 {
1425 case EOpAny:
1426 case EOpAll:
1427 case EOpLength:
1428 case EOpTranspose:
1429 case EOpDeterminant:
1430 case EOpInverse:
1431 case EOpPackSnorm2x16:
1432 case EOpUnpackSnorm2x16:
1433 case EOpPackUnorm2x16:
1434 case EOpUnpackUnorm2x16:
1435 case EOpPackHalf2x16:
1436 case EOpUnpackHalf2x16:
1437 case EOpPackUnorm4x8:
1438 case EOpPackSnorm4x8:
1439 case EOpUnpackUnorm4x8:
1440 case EOpUnpackSnorm4x8:
1441 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1442 break;
1443 default:
1444 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1445 break;
1446 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301447 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001448 if (constArray == nullptr)
1449 {
1450 return this;
1451 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001452 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001453}
1454
Olli Etuahof119a262016-08-19 15:54:22 +03001455TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001456{
1457 // Make sure that all params are constant before actual constant folding.
1458 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001459 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001460 if (param->getAsConstantUnion() == nullptr)
1461 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001462 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001463 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001464 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001465 TConstantUnion *constArray = nullptr;
1466 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001467 {
Olli Etuaho765924f2018-01-04 12:48:36 +02001468 // TODO(oetuaho@nvidia.com): Add support for folding array constructors.
1469 if (!isArray())
1470 {
1471 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
1472 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001473 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001474 else if (CanFoldAggregateBuiltInOp(mOp))
Olli Etuaho2768bc82017-12-12 11:51:48 +02001475 {
Olli Etuahof119a262016-08-19 15:54:22 +03001476 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001477 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001478 if (constArray == nullptr)
1479 {
1480 return this;
1481 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001482 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001483}
1484
Jamie Madillb1a85f42014-08-19 15:23:24 -04001485//
1486// The fold functions see if an operation on a constant can be done in place,
1487// without generating run-time code.
1488//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001489// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001490//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001491TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1492 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001493 TDiagnostics *diagnostics,
1494 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001495{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001496 const TConstantUnion *leftArray = getUnionArrayPointer();
1497 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001498
Olli Etuahof119a262016-08-19 15:54:22 +03001499 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001500
1501 size_t objectSize = getType().getObjectSize();
1502
1503 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1504 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1505 {
1506 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1507 }
1508 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1509 {
1510 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001511 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001512 objectSize = rightNode->getType().getObjectSize();
1513 }
1514
1515 TConstantUnion *resultArray = nullptr;
1516
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001517 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001518 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001519 case EOpAdd:
1520 resultArray = new TConstantUnion[objectSize];
1521 for (size_t i = 0; i < objectSize; i++)
1522 resultArray[i] =
1523 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1524 break;
1525 case EOpSub:
1526 resultArray = new TConstantUnion[objectSize];
1527 for (size_t i = 0; i < objectSize; i++)
1528 resultArray[i] =
1529 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1530 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001531
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001532 case EOpMul:
1533 case EOpVectorTimesScalar:
1534 case EOpMatrixTimesScalar:
1535 resultArray = new TConstantUnion[objectSize];
1536 for (size_t i = 0; i < objectSize; i++)
1537 resultArray[i] =
1538 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1539 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001540
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001541 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001542 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001543 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001544 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001545
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001546 const int leftCols = getCols();
1547 const int leftRows = getRows();
1548 const int rightCols = rightNode->getType().getCols();
1549 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001550 const int resultCols = rightCols;
1551 const int resultRows = leftRows;
1552
1553 resultArray = new TConstantUnion[resultCols * resultRows];
1554 for (int row = 0; row < resultRows; row++)
1555 {
1556 for (int column = 0; column < resultCols; column++)
1557 {
1558 resultArray[resultRows * column + row].setFConst(0.0f);
1559 for (int i = 0; i < leftCols; i++)
1560 {
1561 resultArray[resultRows * column + row].setFConst(
1562 resultArray[resultRows * column + row].getFConst() +
1563 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001564 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001565 }
1566 }
1567 }
1568 }
1569 break;
1570
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001571 case EOpDiv:
1572 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001573 {
1574 resultArray = new TConstantUnion[objectSize];
1575 for (size_t i = 0; i < objectSize; i++)
1576 {
1577 switch (getType().getBasicType())
1578 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001579 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001580 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001581 ASSERT(op == EOpDiv);
1582 float dividend = leftArray[i].getFConst();
1583 float divisor = rightArray[i].getFConst();
1584 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001585 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001586 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001587 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001588 diagnostics->warning(
1589 getLine(),
1590 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001591 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001592 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001593 }
1594 else
1595 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001596 diagnostics->warning(getLine(),
1597 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001598 bool negativeResult =
1599 std::signbit(dividend) != std::signbit(divisor);
1600 resultArray[i].setFConst(
1601 negativeResult ? -std::numeric_limits<float>::infinity()
1602 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001603 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001604 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001605 else if (gl::isInf(dividend) && gl::isInf(divisor))
1606 {
1607 diagnostics->warning(getLine(),
1608 "Infinity divided by infinity during constant "
1609 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001610 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001611 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1612 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001613 else
1614 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001615 float result = dividend / divisor;
1616 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001617 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 diagnostics->warning(
1619 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001620 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001621 }
1622 resultArray[i].setFConst(result);
1623 }
1624 break;
1625 }
1626 case EbtInt:
1627 if (rightArray[i] == 0)
1628 {
1629 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001630 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001631 resultArray[i].setIConst(INT_MAX);
1632 }
1633 else
1634 {
1635 int lhs = leftArray[i].getIConst();
1636 int divisor = rightArray[i].getIConst();
1637 if (op == EOpDiv)
1638 {
1639 // Check for the special case where the minimum representable number
1640 // is
1641 // divided by -1. If left alone this leads to integer overflow in
1642 // C++.
1643 // ESSL 3.00.6 section 4.1.3 Integers:
1644 // "However, for the case where the minimum representable value is
1645 // divided by -1, it is allowed to return either the minimum
1646 // representable value or the maximum representable value."
1647 if (lhs == -0x7fffffff - 1 && divisor == -1)
1648 {
1649 resultArray[i].setIConst(0x7fffffff);
1650 }
1651 else
1652 {
1653 resultArray[i].setIConst(lhs / divisor);
1654 }
Olli Etuahod4453572016-09-27 13:21:46 +01001655 }
1656 else
1657 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001658 ASSERT(op == EOpIMod);
1659 if (lhs < 0 || divisor < 0)
1660 {
1661 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1662 // when
1663 // either one of the operands is negative.
1664 diagnostics->warning(getLine(),
1665 "Negative modulus operator operand "
1666 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001667 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001668 resultArray[i].setIConst(0);
1669 }
1670 else
1671 {
1672 resultArray[i].setIConst(lhs % divisor);
1673 }
Olli Etuahod4453572016-09-27 13:21:46 +01001674 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001675 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001676 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001677
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001678 case EbtUInt:
1679 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001680 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001681 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001682 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001683 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001684 }
1685 else
1686 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001687 if (op == EOpDiv)
1688 {
1689 resultArray[i].setUConst(leftArray[i].getUConst() /
1690 rightArray[i].getUConst());
1691 }
1692 else
1693 {
1694 ASSERT(op == EOpIMod);
1695 resultArray[i].setUConst(leftArray[i].getUConst() %
1696 rightArray[i].getUConst());
1697 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001698 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001699 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001700
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001701 default:
1702 UNREACHABLE();
1703 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001704 }
1705 }
1706 }
1707 break;
1708
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001709 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001710 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001711 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001712 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001713
1714 const int matrixCols = getCols();
1715 const int matrixRows = getRows();
1716
1717 resultArray = new TConstantUnion[matrixRows];
1718
1719 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1720 {
1721 resultArray[matrixRow].setFConst(0.0f);
1722 for (int col = 0; col < matrixCols; col++)
1723 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001724 resultArray[matrixRow].setFConst(
1725 resultArray[matrixRow].getFConst() +
1726 leftArray[col * matrixRows + matrixRow].getFConst() *
1727 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001728 }
1729 }
1730 }
1731 break;
1732
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001733 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001734 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001735 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001736 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001737
1738 const int matrixCols = rightNode->getType().getCols();
1739 const int matrixRows = rightNode->getType().getRows();
1740
1741 resultArray = new TConstantUnion[matrixCols];
1742
1743 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1744 {
1745 resultArray[matrixCol].setFConst(0.0f);
1746 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1747 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001748 resultArray[matrixCol].setFConst(
1749 resultArray[matrixCol].getFConst() +
1750 leftArray[matrixRow].getFConst() *
1751 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001752 }
1753 }
1754 }
1755 break;
1756
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001757 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001758 {
1759 resultArray = new TConstantUnion[objectSize];
1760 for (size_t i = 0; i < objectSize; i++)
1761 {
1762 resultArray[i] = leftArray[i] && rightArray[i];
1763 }
1764 }
1765 break;
1766
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001767 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001768 {
1769 resultArray = new TConstantUnion[objectSize];
1770 for (size_t i = 0; i < objectSize; i++)
1771 {
1772 resultArray[i] = leftArray[i] || rightArray[i];
1773 }
1774 }
1775 break;
1776
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001777 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001778 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001779 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001780 resultArray = new TConstantUnion[objectSize];
1781 for (size_t i = 0; i < objectSize; i++)
1782 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001783 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001784 }
1785 }
1786 break;
1787
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001788 case EOpBitwiseAnd:
1789 resultArray = new TConstantUnion[objectSize];
1790 for (size_t i = 0; i < objectSize; i++)
1791 resultArray[i] = leftArray[i] & rightArray[i];
1792 break;
1793 case EOpBitwiseXor:
1794 resultArray = new TConstantUnion[objectSize];
1795 for (size_t i = 0; i < objectSize; i++)
1796 resultArray[i] = leftArray[i] ^ rightArray[i];
1797 break;
1798 case EOpBitwiseOr:
1799 resultArray = new TConstantUnion[objectSize];
1800 for (size_t i = 0; i < objectSize; i++)
1801 resultArray[i] = leftArray[i] | rightArray[i];
1802 break;
1803 case EOpBitShiftLeft:
1804 resultArray = new TConstantUnion[objectSize];
1805 for (size_t i = 0; i < objectSize; i++)
1806 resultArray[i] =
1807 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1808 break;
1809 case EOpBitShiftRight:
1810 resultArray = new TConstantUnion[objectSize];
1811 for (size_t i = 0; i < objectSize; i++)
1812 resultArray[i] =
1813 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1814 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001815
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001816 case EOpLessThan:
1817 ASSERT(objectSize == 1);
1818 resultArray = new TConstantUnion[1];
1819 resultArray->setBConst(*leftArray < *rightArray);
1820 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001821
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001822 case EOpGreaterThan:
1823 ASSERT(objectSize == 1);
1824 resultArray = new TConstantUnion[1];
1825 resultArray->setBConst(*leftArray > *rightArray);
1826 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001827
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001828 case EOpLessThanEqual:
1829 ASSERT(objectSize == 1);
1830 resultArray = new TConstantUnion[1];
1831 resultArray->setBConst(!(*leftArray > *rightArray));
1832 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001833
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001834 case EOpGreaterThanEqual:
1835 ASSERT(objectSize == 1);
1836 resultArray = new TConstantUnion[1];
1837 resultArray->setBConst(!(*leftArray < *rightArray));
1838 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001839
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001840 case EOpEqual:
1841 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001842 {
1843 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001844 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001845 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001846 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001847 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001848 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001849 equal = false;
1850 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001851 }
1852 }
1853 if (op == EOpEqual)
1854 {
1855 resultArray->setBConst(equal);
1856 }
1857 else
1858 {
1859 resultArray->setBConst(!equal);
1860 }
1861 }
1862 break;
1863
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001864 default:
1865 UNREACHABLE();
1866 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001867 }
1868 return resultArray;
1869}
1870
Olli Etuahof119a262016-08-19 15:54:22 +03001871// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1872// code. Returns the constant value to keep using. Nullptr should not be returned.
1873TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001874{
Olli Etuahof119a262016-08-19 15:54:22 +03001875 // Do operations where the return type may have a different number of components compared to the
1876 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001877
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001878 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001879 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301880
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001881 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301882 TConstantUnion *resultArray = nullptr;
1883 switch (op)
1884 {
Olli Etuahof119a262016-08-19 15:54:22 +03001885 case EOpAny:
1886 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301887 resultArray = new TConstantUnion();
1888 resultArray->setBConst(false);
1889 for (size_t i = 0; i < objectSize; i++)
1890 {
1891 if (operandArray[i].getBConst())
1892 {
1893 resultArray->setBConst(true);
1894 break;
1895 }
1896 }
1897 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301898
Olli Etuahof119a262016-08-19 15:54:22 +03001899 case EOpAll:
1900 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301901 resultArray = new TConstantUnion();
1902 resultArray->setBConst(true);
1903 for (size_t i = 0; i < objectSize; i++)
1904 {
1905 if (!operandArray[i].getBConst())
1906 {
1907 resultArray->setBConst(false);
1908 break;
1909 }
1910 }
1911 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301912
Olli Etuahof119a262016-08-19 15:54:22 +03001913 case EOpLength:
1914 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301915 resultArray = new TConstantUnion();
1916 resultArray->setFConst(VectorLength(operandArray, objectSize));
1917 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301918
Olli Etuahof119a262016-08-19 15:54:22 +03001919 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301920 {
Olli Etuahof119a262016-08-19 15:54:22 +03001921 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301922 resultArray = new TConstantUnion[objectSize];
1923 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001924 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301925 SetUnionArrayFromMatrix(result, resultArray);
1926 break;
1927 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301928
Olli Etuahof119a262016-08-19 15:54:22 +03001929 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301930 {
Olli Etuahof119a262016-08-19 15:54:22 +03001931 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301932 unsigned int size = getType().getNominalSize();
1933 ASSERT(size >= 2 && size <= 4);
1934 resultArray = new TConstantUnion();
1935 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1936 break;
1937 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301938
Olli Etuahof119a262016-08-19 15:54:22 +03001939 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301940 {
Olli Etuahof119a262016-08-19 15:54:22 +03001941 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301942 unsigned int size = getType().getNominalSize();
1943 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001944 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1946 SetUnionArrayFromMatrix(result, resultArray);
1947 break;
1948 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301949
Olli Etuahof119a262016-08-19 15:54:22 +03001950 case EOpPackSnorm2x16:
1951 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301952 ASSERT(getType().getNominalSize() == 2);
1953 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001954 resultArray->setUConst(
1955 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301956 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301957
Olli Etuahof119a262016-08-19 15:54:22 +03001958 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301959 {
Olli Etuahof119a262016-08-19 15:54:22 +03001960 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301961 resultArray = new TConstantUnion[2];
1962 float f1, f2;
1963 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1964 resultArray[0].setFConst(f1);
1965 resultArray[1].setFConst(f2);
1966 break;
1967 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301968
Olli Etuahof119a262016-08-19 15:54:22 +03001969 case EOpPackUnorm2x16:
1970 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301971 ASSERT(getType().getNominalSize() == 2);
1972 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001973 resultArray->setUConst(
1974 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301975 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301976
Olli Etuahof119a262016-08-19 15:54:22 +03001977 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301978 {
Olli Etuahof119a262016-08-19 15:54:22 +03001979 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301980 resultArray = new TConstantUnion[2];
1981 float f1, f2;
1982 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1983 resultArray[0].setFConst(f1);
1984 resultArray[1].setFConst(f2);
1985 break;
1986 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301987
Olli Etuahof119a262016-08-19 15:54:22 +03001988 case EOpPackHalf2x16:
1989 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301990 ASSERT(getType().getNominalSize() == 2);
1991 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001992 resultArray->setUConst(
1993 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301994 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301995
Olli Etuahof119a262016-08-19 15:54:22 +03001996 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301997 {
Olli Etuahof119a262016-08-19 15:54:22 +03001998 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301999 resultArray = new TConstantUnion[2];
2000 float f1, f2;
2001 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2002 resultArray[0].setFConst(f1);
2003 resultArray[1].setFConst(f2);
2004 break;
2005 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302006
Olli Etuaho25aef452017-01-29 16:15:44 -08002007 case EOpPackUnorm4x8:
2008 {
2009 ASSERT(getType().getBasicType() == EbtFloat);
2010 resultArray = new TConstantUnion();
2011 resultArray->setUConst(
2012 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2013 operandArray[2].getFConst(), operandArray[3].getFConst()));
2014 break;
2015 }
2016 case EOpPackSnorm4x8:
2017 {
2018 ASSERT(getType().getBasicType() == EbtFloat);
2019 resultArray = new TConstantUnion();
2020 resultArray->setUConst(
2021 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2022 operandArray[2].getFConst(), operandArray[3].getFConst()));
2023 break;
2024 }
2025 case EOpUnpackUnorm4x8:
2026 {
2027 ASSERT(getType().getBasicType() == EbtUInt);
2028 resultArray = new TConstantUnion[4];
2029 float f[4];
2030 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2031 for (size_t i = 0; i < 4; ++i)
2032 {
2033 resultArray[i].setFConst(f[i]);
2034 }
2035 break;
2036 }
2037 case EOpUnpackSnorm4x8:
2038 {
2039 ASSERT(getType().getBasicType() == EbtUInt);
2040 resultArray = new TConstantUnion[4];
2041 float f[4];
2042 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2043 for (size_t i = 0; i < 4; ++i)
2044 {
2045 resultArray[i].setFConst(f[i]);
2046 }
2047 break;
2048 }
2049
Olli Etuahof119a262016-08-19 15:54:22 +03002050 default:
2051 UNREACHABLE();
2052 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302053 }
2054
2055 return resultArray;
2056}
2057
Olli Etuahof119a262016-08-19 15:54:22 +03002058TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2059 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302060{
Olli Etuahof119a262016-08-19 15:54:22 +03002061 // Do unary operations where each component of the result is computed based on the corresponding
2062 // component of the operand. Also folds normalize, though the divisor in that case takes all
2063 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302064
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002065 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002066 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002067
2068 size_t objectSize = getType().getObjectSize();
2069
Arun Patoleab2b9a22015-07-06 18:27:56 +05302070 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2071 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302072 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002073 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302074 {
Olli Etuahof119a262016-08-19 15:54:22 +03002075 case EOpNegative:
2076 switch (getType().getBasicType())
2077 {
2078 case EbtFloat:
2079 resultArray[i].setFConst(-operandArray[i].getFConst());
2080 break;
2081 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002082 if (operandArray[i] == std::numeric_limits<int>::min())
2083 {
2084 // The minimum representable integer doesn't have a positive
2085 // counterpart, rather the negation overflows and in ESSL is supposed to
2086 // wrap back to the minimum representable integer. Make sure that we
2087 // don't actually let the negation overflow, which has undefined
2088 // behavior in C++.
2089 resultArray[i].setIConst(std::numeric_limits<int>::min());
2090 }
2091 else
2092 {
2093 resultArray[i].setIConst(-operandArray[i].getIConst());
2094 }
Olli Etuahof119a262016-08-19 15:54:22 +03002095 break;
2096 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002097 if (operandArray[i] == 0x80000000u)
2098 {
2099 resultArray[i].setUConst(0x80000000u);
2100 }
2101 else
2102 {
2103 resultArray[i].setUConst(static_cast<unsigned int>(
2104 -static_cast<int>(operandArray[i].getUConst())));
2105 }
Olli Etuahof119a262016-08-19 15:54:22 +03002106 break;
2107 default:
2108 UNREACHABLE();
2109 return nullptr;
2110 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302111 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302112
Olli Etuahof119a262016-08-19 15:54:22 +03002113 case EOpPositive:
2114 switch (getType().getBasicType())
2115 {
2116 case EbtFloat:
2117 resultArray[i].setFConst(operandArray[i].getFConst());
2118 break;
2119 case EbtInt:
2120 resultArray[i].setIConst(operandArray[i].getIConst());
2121 break;
2122 case EbtUInt:
2123 resultArray[i].setUConst(static_cast<unsigned int>(
2124 static_cast<int>(operandArray[i].getUConst())));
2125 break;
2126 default:
2127 UNREACHABLE();
2128 return nullptr;
2129 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302130 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302131
Olli Etuahof119a262016-08-19 15:54:22 +03002132 case EOpLogicalNot:
2133 switch (getType().getBasicType())
2134 {
2135 case EbtBool:
2136 resultArray[i].setBConst(!operandArray[i].getBConst());
2137 break;
2138 default:
2139 UNREACHABLE();
2140 return nullptr;
2141 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302142 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302143
Olli Etuahof119a262016-08-19 15:54:22 +03002144 case EOpBitwiseNot:
2145 switch (getType().getBasicType())
2146 {
2147 case EbtInt:
2148 resultArray[i].setIConst(~operandArray[i].getIConst());
2149 break;
2150 case EbtUInt:
2151 resultArray[i].setUConst(~operandArray[i].getUConst());
2152 break;
2153 default:
2154 UNREACHABLE();
2155 return nullptr;
2156 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302157 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302158
Olli Etuahof119a262016-08-19 15:54:22 +03002159 case EOpRadians:
2160 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302161 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2162 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302163
Olli Etuahof119a262016-08-19 15:54:22 +03002164 case EOpDegrees:
2165 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302166 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2167 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302168
Olli Etuahof119a262016-08-19 15:54:22 +03002169 case EOpSin:
2170 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302171 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302172
Olli Etuahof119a262016-08-19 15:54:22 +03002173 case EOpCos:
2174 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2175 break;
2176
2177 case EOpTan:
2178 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2179 break;
2180
2181 case EOpAsin:
2182 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2183 // 0.
2184 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2185 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2186 diagnostics, &resultArray[i]);
2187 else
2188 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2189 break;
2190
2191 case EOpAcos:
2192 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2193 // 0.
2194 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2195 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2196 diagnostics, &resultArray[i]);
2197 else
2198 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2199 break;
2200
2201 case EOpAtan:
2202 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2203 break;
2204
2205 case EOpSinh:
2206 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2207 break;
2208
2209 case EOpCosh:
2210 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2211 break;
2212
2213 case EOpTanh:
2214 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2215 break;
2216
2217 case EOpAsinh:
2218 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2219 break;
2220
2221 case EOpAcosh:
2222 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2223 if (operandArray[i].getFConst() < 1.0f)
2224 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2225 diagnostics, &resultArray[i]);
2226 else
2227 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2228 break;
2229
2230 case EOpAtanh:
2231 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2232 // 0.
2233 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2234 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2235 diagnostics, &resultArray[i]);
2236 else
2237 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2238 break;
2239
2240 case EOpAbs:
2241 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302242 {
Olli Etuahof119a262016-08-19 15:54:22 +03002243 case EbtFloat:
2244 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2245 break;
2246 case EbtInt:
2247 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2248 break;
2249 default:
2250 UNREACHABLE();
2251 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302252 }
2253 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002254
2255 case EOpSign:
2256 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302257 {
Olli Etuahof119a262016-08-19 15:54:22 +03002258 case EbtFloat:
2259 {
2260 float fConst = operandArray[i].getFConst();
2261 float fResult = 0.0f;
2262 if (fConst > 0.0f)
2263 fResult = 1.0f;
2264 else if (fConst < 0.0f)
2265 fResult = -1.0f;
2266 resultArray[i].setFConst(fResult);
2267 break;
2268 }
2269 case EbtInt:
2270 {
2271 int iConst = operandArray[i].getIConst();
2272 int iResult = 0;
2273 if (iConst > 0)
2274 iResult = 1;
2275 else if (iConst < 0)
2276 iResult = -1;
2277 resultArray[i].setIConst(iResult);
2278 break;
2279 }
2280 default:
2281 UNREACHABLE();
2282 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302283 }
2284 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302285
Olli Etuahof119a262016-08-19 15:54:22 +03002286 case EOpFloor:
2287 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2288 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302289
Olli Etuahof119a262016-08-19 15:54:22 +03002290 case EOpTrunc:
2291 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2292 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302293
Olli Etuahof119a262016-08-19 15:54:22 +03002294 case EOpRound:
2295 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2296 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302297
Olli Etuahof119a262016-08-19 15:54:22 +03002298 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302299 {
Olli Etuahof119a262016-08-19 15:54:22 +03002300 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302301 float x = operandArray[i].getFConst();
2302 float result;
2303 float fractPart = modff(x, &result);
2304 if (fabsf(fractPart) == 0.5f)
2305 result = 2.0f * roundf(x / 2.0f);
2306 else
2307 result = roundf(x);
2308 resultArray[i].setFConst(result);
2309 break;
2310 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302311
Olli Etuahof119a262016-08-19 15:54:22 +03002312 case EOpCeil:
2313 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2314 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302315
Olli Etuahof119a262016-08-19 15:54:22 +03002316 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302317 {
Olli Etuahof119a262016-08-19 15:54:22 +03002318 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302319 float x = operandArray[i].getFConst();
2320 resultArray[i].setFConst(x - floorf(x));
2321 break;
2322 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302323
Olli Etuahof119a262016-08-19 15:54:22 +03002324 case EOpIsNan:
2325 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302326 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2327 break;
Arun Patole551279e2015-07-07 18:18:23 +05302328
Olli Etuahof119a262016-08-19 15:54:22 +03002329 case EOpIsInf:
2330 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302331 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2332 break;
Arun Patole551279e2015-07-07 18:18:23 +05302333
Olli Etuahof119a262016-08-19 15:54:22 +03002334 case EOpFloatBitsToInt:
2335 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302336 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2337 break;
Arun Patole551279e2015-07-07 18:18:23 +05302338
Olli Etuahof119a262016-08-19 15:54:22 +03002339 case EOpFloatBitsToUint:
2340 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302341 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2342 break;
Arun Patole551279e2015-07-07 18:18:23 +05302343
Olli Etuahof119a262016-08-19 15:54:22 +03002344 case EOpIntBitsToFloat:
2345 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302346 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2347 break;
Arun Patole551279e2015-07-07 18:18:23 +05302348
Olli Etuahof119a262016-08-19 15:54:22 +03002349 case EOpUintBitsToFloat:
2350 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302351 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2352 break;
Arun Patole551279e2015-07-07 18:18:23 +05302353
Olli Etuahof119a262016-08-19 15:54:22 +03002354 case EOpExp:
2355 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2356 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302357
Olli Etuahof119a262016-08-19 15:54:22 +03002358 case EOpLog:
2359 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2360 if (operandArray[i].getFConst() <= 0.0f)
2361 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2362 diagnostics, &resultArray[i]);
2363 else
2364 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2365 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302366
Olli Etuahof119a262016-08-19 15:54:22 +03002367 case EOpExp2:
2368 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2369 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302370
Olli Etuahof119a262016-08-19 15:54:22 +03002371 case EOpLog2:
2372 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2373 // And log2f is not available on some plarforms like old android, so just using
2374 // log(x)/log(2) here.
2375 if (operandArray[i].getFConst() <= 0.0f)
2376 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2377 diagnostics, &resultArray[i]);
2378 else
2379 {
2380 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2381 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2382 }
2383 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302384
Olli Etuahof119a262016-08-19 15:54:22 +03002385 case EOpSqrt:
2386 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2387 if (operandArray[i].getFConst() < 0.0f)
2388 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2389 diagnostics, &resultArray[i]);
2390 else
2391 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2392 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302393
Olli Etuahof119a262016-08-19 15:54:22 +03002394 case EOpInverseSqrt:
2395 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2396 // so getting the square root first using builtin function sqrt() and then taking
2397 // its inverse.
2398 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2399 // result to 0.
2400 if (operandArray[i].getFConst() <= 0.0f)
2401 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2402 diagnostics, &resultArray[i]);
2403 else
2404 {
2405 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2406 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2407 }
2408 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302409
Olli Etuahod68924e2017-01-02 17:34:40 +00002410 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002411 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302412 resultArray[i].setBConst(!operandArray[i].getBConst());
2413 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302414
Olli Etuahof119a262016-08-19 15:54:22 +03002415 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302416 {
Olli Etuahof119a262016-08-19 15:54:22 +03002417 ASSERT(getType().getBasicType() == EbtFloat);
2418 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302419 float length = VectorLength(operandArray, objectSize);
2420 if (length)
2421 resultArray[i].setFConst(x / length);
2422 else
Olli Etuahof119a262016-08-19 15:54:22 +03002423 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2424 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302425 break;
2426 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002427 case EOpBitfieldReverse:
2428 {
2429 uint32_t value;
2430 if (getType().getBasicType() == EbtInt)
2431 {
2432 value = static_cast<uint32_t>(operandArray[i].getIConst());
2433 }
2434 else
2435 {
2436 ASSERT(getType().getBasicType() == EbtUInt);
2437 value = operandArray[i].getUConst();
2438 }
2439 uint32_t result = gl::BitfieldReverse(value);
2440 if (getType().getBasicType() == EbtInt)
2441 {
2442 resultArray[i].setIConst(static_cast<int32_t>(result));
2443 }
2444 else
2445 {
2446 resultArray[i].setUConst(result);
2447 }
2448 break;
2449 }
2450 case EOpBitCount:
2451 {
2452 uint32_t value;
2453 if (getType().getBasicType() == EbtInt)
2454 {
2455 value = static_cast<uint32_t>(operandArray[i].getIConst());
2456 }
2457 else
2458 {
2459 ASSERT(getType().getBasicType() == EbtUInt);
2460 value = operandArray[i].getUConst();
2461 }
2462 int result = gl::BitCount(value);
2463 resultArray[i].setIConst(result);
2464 break;
2465 }
2466 case EOpFindLSB:
2467 {
2468 uint32_t value;
2469 if (getType().getBasicType() == EbtInt)
2470 {
2471 value = static_cast<uint32_t>(operandArray[i].getIConst());
2472 }
2473 else
2474 {
2475 ASSERT(getType().getBasicType() == EbtUInt);
2476 value = operandArray[i].getUConst();
2477 }
2478 resultArray[i].setIConst(gl::FindLSB(value));
2479 break;
2480 }
2481 case EOpFindMSB:
2482 {
2483 uint32_t value;
2484 if (getType().getBasicType() == EbtInt)
2485 {
2486 int intValue = operandArray[i].getIConst();
2487 value = static_cast<uint32_t>(intValue);
2488 if (intValue < 0)
2489 {
2490 // Look for zero instead of one in value. This also handles the intValue ==
2491 // -1 special case, where the return value needs to be -1.
2492 value = ~value;
2493 }
2494 }
2495 else
2496 {
2497 ASSERT(getType().getBasicType() == EbtUInt);
2498 value = operandArray[i].getUConst();
2499 }
2500 resultArray[i].setIConst(gl::FindMSB(value));
2501 break;
2502 }
Olli Etuahof119a262016-08-19 15:54:22 +03002503 case EOpDFdx:
2504 case EOpDFdy:
2505 case EOpFwidth:
2506 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302507 // Derivatives of constant arguments should be 0.
2508 resultArray[i].setFConst(0.0f);
2509 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302510
Olli Etuahof119a262016-08-19 15:54:22 +03002511 default:
2512 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302513 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302514 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002515
Arun Patoleab2b9a22015-07-06 18:27:56 +05302516 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002517}
2518
Olli Etuahof119a262016-08-19 15:54:22 +03002519void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2520 FloatTypeUnaryFunc builtinFunc,
2521 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302522{
2523 ASSERT(builtinFunc);
2524
Olli Etuahof119a262016-08-19 15:54:22 +03002525 ASSERT(getType().getBasicType() == EbtFloat);
2526 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302527}
2528
Jamie Madillb1a85f42014-08-19 15:23:24 -04002529// static
Olli Etuahof119a262016-08-19 15:54:22 +03002530TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002531{
2532 ASSERT(aggregate->getSequence()->size() > 0u);
2533 size_t resultSize = aggregate->getType().getObjectSize();
2534 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2535 TBasicType basicType = aggregate->getBasicType();
2536
2537 size_t resultIndex = 0u;
2538
2539 if (aggregate->getSequence()->size() == 1u)
2540 {
2541 TIntermNode *argument = aggregate->getSequence()->front();
2542 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2543 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2544 // Check the special case of constructing a matrix diagonal from a single scalar,
2545 // or a vector from a single scalar.
2546 if (argumentConstant->getType().getObjectSize() == 1u)
2547 {
2548 if (aggregate->isMatrix())
2549 {
2550 int resultCols = aggregate->getType().getCols();
2551 int resultRows = aggregate->getType().getRows();
2552 for (int col = 0; col < resultCols; ++col)
2553 {
2554 for (int row = 0; row < resultRows; ++row)
2555 {
2556 if (col == row)
2557 {
2558 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2559 }
2560 else
2561 {
2562 resultArray[resultIndex].setFConst(0.0f);
2563 }
2564 ++resultIndex;
2565 }
2566 }
2567 }
2568 else
2569 {
2570 while (resultIndex < resultSize)
2571 {
2572 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2573 ++resultIndex;
2574 }
2575 }
2576 ASSERT(resultIndex == resultSize);
2577 return resultArray;
2578 }
2579 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2580 {
2581 // The special case of constructing a matrix from a matrix.
2582 int argumentCols = argumentConstant->getType().getCols();
2583 int argumentRows = argumentConstant->getType().getRows();
2584 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002585 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002586 for (int col = 0; col < resultCols; ++col)
2587 {
2588 for (int row = 0; row < resultRows; ++row)
2589 {
2590 if (col < argumentCols && row < argumentRows)
2591 {
2592 resultArray[resultIndex].cast(basicType,
2593 argumentUnionArray[col * argumentRows + row]);
2594 }
2595 else if (col == row)
2596 {
2597 resultArray[resultIndex].setFConst(1.0f);
2598 }
2599 else
2600 {
2601 resultArray[resultIndex].setFConst(0.0f);
2602 }
2603 ++resultIndex;
2604 }
2605 }
2606 ASSERT(resultIndex == resultSize);
2607 return resultArray;
2608 }
2609 }
2610
2611 for (TIntermNode *&argument : *aggregate->getSequence())
2612 {
2613 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2614 size_t argumentSize = argumentConstant->getType().getObjectSize();
2615 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2616 for (size_t i = 0u; i < argumentSize; ++i)
2617 {
2618 if (resultIndex >= resultSize)
2619 break;
2620 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2621 ++resultIndex;
2622 }
2623 }
2624 ASSERT(resultIndex == resultSize);
2625 return resultArray;
2626}
2627
2628// static
Olli Etuahof119a262016-08-19 15:54:22 +03002629TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2630 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302631{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002632 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002633 TIntermSequence *arguments = aggregate->getSequence();
2634 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2635 std::vector<const TConstantUnion *> unionArrays(argsCount);
2636 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002637 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302638 TBasicType basicType = EbtVoid;
2639 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002640 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302641 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002642 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2643 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302644
2645 if (i == 0)
2646 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002647 basicType = argConstant->getType().getBasicType();
2648 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302649 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002650 unionArrays[i] = argConstant->getUnionArrayPointer();
2651 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002652 if (objectSizes[i] > maxObjectSize)
2653 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302654 }
2655
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002656 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302657 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002658 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302659 if (objectSizes[i] != maxObjectSize)
2660 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2661 }
Arun Patole274f0702015-05-05 13:33:30 +05302662
Olli Etuahob43846e2015-06-02 18:18:57 +03002663 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002664
2665 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302666 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002667 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302668 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002669 ASSERT(basicType == EbtFloat);
2670 resultArray = new TConstantUnion[maxObjectSize];
2671 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302672 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002673 float y = unionArrays[0][i].getFConst();
2674 float x = unionArrays[1][i].getFConst();
2675 // Results are undefined if x and y are both 0.
2676 if (x == 0.0f && y == 0.0f)
2677 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2678 else
2679 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302680 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002681 break;
2682 }
Arun Patolebf790422015-05-18 17:53:04 +05302683
Olli Etuaho51182ab2017-01-22 00:12:29 +00002684 case EOpPow:
2685 {
2686 ASSERT(basicType == EbtFloat);
2687 resultArray = new TConstantUnion[maxObjectSize];
2688 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302689 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002690 float x = unionArrays[0][i].getFConst();
2691 float y = unionArrays[1][i].getFConst();
2692 // Results are undefined if x < 0.
2693 // Results are undefined if x = 0 and y <= 0.
2694 if (x < 0.0f)
2695 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2696 else if (x == 0.0f && y <= 0.0f)
2697 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2698 else
2699 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302700 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002701 break;
2702 }
Arun Patolebf790422015-05-18 17:53:04 +05302703
Olli Etuaho51182ab2017-01-22 00:12:29 +00002704 case EOpMod:
2705 {
2706 ASSERT(basicType == EbtFloat);
2707 resultArray = new TConstantUnion[maxObjectSize];
2708 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302709 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002710 float x = unionArrays[0][i].getFConst();
2711 float y = unionArrays[1][i].getFConst();
2712 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302713 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002714 break;
2715 }
Arun Patolebf790422015-05-18 17:53:04 +05302716
Olli Etuaho51182ab2017-01-22 00:12:29 +00002717 case EOpMin:
2718 {
2719 resultArray = new TConstantUnion[maxObjectSize];
2720 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302721 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002722 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302723 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002724 case EbtFloat:
2725 resultArray[i].setFConst(
2726 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2727 break;
2728 case EbtInt:
2729 resultArray[i].setIConst(
2730 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2731 break;
2732 case EbtUInt:
2733 resultArray[i].setUConst(
2734 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2735 break;
2736 default:
2737 UNREACHABLE();
2738 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302739 }
2740 }
2741 break;
Arun Patole274f0702015-05-05 13:33:30 +05302742 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002743
2744 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302745 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002746 resultArray = new TConstantUnion[maxObjectSize];
2747 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302748 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002749 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302750 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002751 case EbtFloat:
2752 resultArray[i].setFConst(
2753 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2754 break;
2755 case EbtInt:
2756 resultArray[i].setIConst(
2757 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2758 break;
2759 case EbtUInt:
2760 resultArray[i].setUConst(
2761 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2762 break;
2763 default:
2764 UNREACHABLE();
2765 break;
Arun Patole274f0702015-05-05 13:33:30 +05302766 }
2767 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002768 break;
Arun Patole274f0702015-05-05 13:33:30 +05302769 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002770
2771 case EOpStep:
2772 {
2773 ASSERT(basicType == EbtFloat);
2774 resultArray = new TConstantUnion[maxObjectSize];
2775 for (size_t i = 0; i < maxObjectSize; i++)
2776 resultArray[i].setFConst(
2777 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2778 break;
2779 }
2780
2781 case EOpLessThanComponentWise:
2782 {
2783 resultArray = new TConstantUnion[maxObjectSize];
2784 for (size_t i = 0; i < maxObjectSize; i++)
2785 {
2786 switch (basicType)
2787 {
2788 case EbtFloat:
2789 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2790 unionArrays[1][i].getFConst());
2791 break;
2792 case EbtInt:
2793 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2794 unionArrays[1][i].getIConst());
2795 break;
2796 case EbtUInt:
2797 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2798 unionArrays[1][i].getUConst());
2799 break;
2800 default:
2801 UNREACHABLE();
2802 break;
2803 }
2804 }
2805 break;
2806 }
2807
2808 case EOpLessThanEqualComponentWise:
2809 {
2810 resultArray = new TConstantUnion[maxObjectSize];
2811 for (size_t i = 0; i < maxObjectSize; i++)
2812 {
2813 switch (basicType)
2814 {
2815 case EbtFloat:
2816 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2817 unionArrays[1][i].getFConst());
2818 break;
2819 case EbtInt:
2820 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2821 unionArrays[1][i].getIConst());
2822 break;
2823 case EbtUInt:
2824 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2825 unionArrays[1][i].getUConst());
2826 break;
2827 default:
2828 UNREACHABLE();
2829 break;
2830 }
2831 }
2832 break;
2833 }
2834
2835 case EOpGreaterThanComponentWise:
2836 {
2837 resultArray = new TConstantUnion[maxObjectSize];
2838 for (size_t i = 0; i < maxObjectSize; i++)
2839 {
2840 switch (basicType)
2841 {
2842 case EbtFloat:
2843 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2844 unionArrays[1][i].getFConst());
2845 break;
2846 case EbtInt:
2847 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2848 unionArrays[1][i].getIConst());
2849 break;
2850 case EbtUInt:
2851 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2852 unionArrays[1][i].getUConst());
2853 break;
2854 default:
2855 UNREACHABLE();
2856 break;
2857 }
2858 }
2859 break;
2860 }
2861 case EOpGreaterThanEqualComponentWise:
2862 {
2863 resultArray = new TConstantUnion[maxObjectSize];
2864 for (size_t i = 0; i < maxObjectSize; i++)
2865 {
2866 switch (basicType)
2867 {
2868 case EbtFloat:
2869 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2870 unionArrays[1][i].getFConst());
2871 break;
2872 case EbtInt:
2873 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2874 unionArrays[1][i].getIConst());
2875 break;
2876 case EbtUInt:
2877 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2878 unionArrays[1][i].getUConst());
2879 break;
2880 default:
2881 UNREACHABLE();
2882 break;
2883 }
2884 }
2885 }
2886 break;
2887
2888 case EOpEqualComponentWise:
2889 {
2890 resultArray = new TConstantUnion[maxObjectSize];
2891 for (size_t i = 0; i < maxObjectSize; i++)
2892 {
2893 switch (basicType)
2894 {
2895 case EbtFloat:
2896 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2897 unionArrays[1][i].getFConst());
2898 break;
2899 case EbtInt:
2900 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2901 unionArrays[1][i].getIConst());
2902 break;
2903 case EbtUInt:
2904 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2905 unionArrays[1][i].getUConst());
2906 break;
2907 case EbtBool:
2908 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2909 unionArrays[1][i].getBConst());
2910 break;
2911 default:
2912 UNREACHABLE();
2913 break;
2914 }
2915 }
2916 break;
2917 }
2918
2919 case EOpNotEqualComponentWise:
2920 {
2921 resultArray = new TConstantUnion[maxObjectSize];
2922 for (size_t i = 0; i < maxObjectSize; i++)
2923 {
2924 switch (basicType)
2925 {
2926 case EbtFloat:
2927 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2928 unionArrays[1][i].getFConst());
2929 break;
2930 case EbtInt:
2931 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2932 unionArrays[1][i].getIConst());
2933 break;
2934 case EbtUInt:
2935 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2936 unionArrays[1][i].getUConst());
2937 break;
2938 case EbtBool:
2939 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2940 unionArrays[1][i].getBConst());
2941 break;
2942 default:
2943 UNREACHABLE();
2944 break;
2945 }
2946 }
2947 break;
2948 }
2949
2950 case EOpDistance:
2951 {
2952 ASSERT(basicType == EbtFloat);
2953 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2954 resultArray = new TConstantUnion();
2955 for (size_t i = 0; i < maxObjectSize; i++)
2956 {
2957 float x = unionArrays[0][i].getFConst();
2958 float y = unionArrays[1][i].getFConst();
2959 distanceArray[i].setFConst(x - y);
2960 }
2961 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2962 break;
2963 }
2964
2965 case EOpDot:
2966 ASSERT(basicType == EbtFloat);
2967 resultArray = new TConstantUnion();
2968 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2969 break;
2970
2971 case EOpCross:
2972 {
2973 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2974 resultArray = new TConstantUnion[maxObjectSize];
2975 float x0 = unionArrays[0][0].getFConst();
2976 float x1 = unionArrays[0][1].getFConst();
2977 float x2 = unionArrays[0][2].getFConst();
2978 float y0 = unionArrays[1][0].getFConst();
2979 float y1 = unionArrays[1][1].getFConst();
2980 float y2 = unionArrays[1][2].getFConst();
2981 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2982 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2983 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2984 break;
2985 }
2986
2987 case EOpReflect:
2988 {
2989 ASSERT(basicType == EbtFloat);
2990 // genType reflect (genType I, genType N) :
2991 // For the incident vector I and surface orientation N, returns the reflection
2992 // direction:
2993 // I - 2 * dot(N, I) * N.
2994 resultArray = new TConstantUnion[maxObjectSize];
2995 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2996 for (size_t i = 0; i < maxObjectSize; i++)
2997 {
2998 float result = unionArrays[0][i].getFConst() -
2999 2.0f * dotProduct * unionArrays[1][i].getFConst();
3000 resultArray[i].setFConst(result);
3001 }
3002 break;
3003 }
3004
3005 case EOpMulMatrixComponentWise:
3006 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003007 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3008 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003009 // Perform component-wise matrix multiplication.
3010 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003011 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003012 angle::Matrix<float> result =
3013 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3014 SetUnionArrayFromMatrix(result, resultArray);
3015 break;
3016 }
3017
3018 case EOpOuterProduct:
3019 {
3020 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003021 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3022 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003023 resultArray = new TConstantUnion[numRows * numCols];
3024 angle::Matrix<float> result =
3025 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3026 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3027 SetUnionArrayFromMatrix(result, resultArray);
3028 break;
3029 }
3030
3031 case EOpClamp:
3032 {
3033 resultArray = new TConstantUnion[maxObjectSize];
3034 for (size_t i = 0; i < maxObjectSize; i++)
3035 {
3036 switch (basicType)
3037 {
3038 case EbtFloat:
3039 {
3040 float x = unionArrays[0][i].getFConst();
3041 float min = unionArrays[1][i].getFConst();
3042 float max = unionArrays[2][i].getFConst();
3043 // Results are undefined if min > max.
3044 if (min > max)
3045 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3046 &resultArray[i]);
3047 else
3048 resultArray[i].setFConst(gl::clamp(x, min, max));
3049 break;
3050 }
3051
3052 case EbtInt:
3053 {
3054 int x = unionArrays[0][i].getIConst();
3055 int min = unionArrays[1][i].getIConst();
3056 int max = unionArrays[2][i].getIConst();
3057 // Results are undefined if min > max.
3058 if (min > max)
3059 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3060 &resultArray[i]);
3061 else
3062 resultArray[i].setIConst(gl::clamp(x, min, max));
3063 break;
3064 }
3065 case EbtUInt:
3066 {
3067 unsigned int x = unionArrays[0][i].getUConst();
3068 unsigned int min = unionArrays[1][i].getUConst();
3069 unsigned int max = unionArrays[2][i].getUConst();
3070 // Results are undefined if min > max.
3071 if (min > max)
3072 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3073 &resultArray[i]);
3074 else
3075 resultArray[i].setUConst(gl::clamp(x, min, max));
3076 break;
3077 }
3078 default:
3079 UNREACHABLE();
3080 break;
3081 }
3082 }
3083 break;
3084 }
3085
3086 case EOpMix:
3087 {
3088 ASSERT(basicType == EbtFloat);
3089 resultArray = new TConstantUnion[maxObjectSize];
3090 for (size_t i = 0; i < maxObjectSize; i++)
3091 {
3092 float x = unionArrays[0][i].getFConst();
3093 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003094 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003095 if (type == EbtFloat)
3096 {
3097 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3098 float a = unionArrays[2][i].getFConst();
3099 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3100 }
3101 else // 3rd parameter is EbtBool
3102 {
3103 ASSERT(type == EbtBool);
3104 // Selects which vector each returned component comes from.
3105 // For a component of a that is false, the corresponding component of x is
3106 // returned.
3107 // For a component of a that is true, the corresponding component of y is
3108 // returned.
3109 bool a = unionArrays[2][i].getBConst();
3110 resultArray[i].setFConst(a ? y : x);
3111 }
3112 }
3113 break;
3114 }
3115
3116 case EOpSmoothStep:
3117 {
3118 ASSERT(basicType == EbtFloat);
3119 resultArray = new TConstantUnion[maxObjectSize];
3120 for (size_t i = 0; i < maxObjectSize; i++)
3121 {
3122 float edge0 = unionArrays[0][i].getFConst();
3123 float edge1 = unionArrays[1][i].getFConst();
3124 float x = unionArrays[2][i].getFConst();
3125 // Results are undefined if edge0 >= edge1.
3126 if (edge0 >= edge1)
3127 {
3128 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3129 }
3130 else
3131 {
3132 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3133 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3134 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3135 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3136 }
3137 }
3138 break;
3139 }
3140
Olli Etuaho74da73f2017-02-01 15:37:48 +00003141 case EOpLdexp:
3142 {
3143 resultArray = new TConstantUnion[maxObjectSize];
3144 for (size_t i = 0; i < maxObjectSize; i++)
3145 {
3146 float x = unionArrays[0][i].getFConst();
3147 int exp = unionArrays[1][i].getIConst();
3148 if (exp > 128)
3149 {
3150 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3151 }
3152 else
3153 {
3154 resultArray[i].setFConst(gl::Ldexp(x, exp));
3155 }
3156 }
3157 break;
3158 }
3159
Jamie Madille72595b2017-06-06 15:12:26 -04003160 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003161 {
3162 ASSERT(basicType == EbtFloat);
3163 // genType faceforward(genType N, genType I, genType Nref) :
3164 // If dot(Nref, I) < 0 return N, otherwise return -N.
3165 resultArray = new TConstantUnion[maxObjectSize];
3166 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3167 for (size_t i = 0; i < maxObjectSize; i++)
3168 {
3169 if (dotProduct < 0)
3170 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3171 else
3172 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3173 }
3174 break;
3175 }
3176
3177 case EOpRefract:
3178 {
3179 ASSERT(basicType == EbtFloat);
3180 // genType refract(genType I, genType N, float eta) :
3181 // For the incident vector I and surface normal N, and the ratio of indices of
3182 // refraction eta,
3183 // return the refraction vector. The result is computed by
3184 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3185 // if (k < 0.0)
3186 // return genType(0.0)
3187 // else
3188 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3189 resultArray = new TConstantUnion[maxObjectSize];
3190 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3191 for (size_t i = 0; i < maxObjectSize; i++)
3192 {
3193 float eta = unionArrays[2][i].getFConst();
3194 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3195 if (k < 0.0f)
3196 resultArray[i].setFConst(0.0f);
3197 else
3198 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3199 (eta * dotProduct + sqrtf(k)) *
3200 unionArrays[1][i].getFConst());
3201 }
3202 break;
3203 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003204 case EOpBitfieldExtract:
3205 {
3206 resultArray = new TConstantUnion[maxObjectSize];
3207 for (size_t i = 0; i < maxObjectSize; ++i)
3208 {
3209 int offset = unionArrays[1][0].getIConst();
3210 int bits = unionArrays[2][0].getIConst();
3211 if (bits == 0)
3212 {
3213 if (aggregate->getBasicType() == EbtInt)
3214 {
3215 resultArray[i].setIConst(0);
3216 }
3217 else
3218 {
3219 ASSERT(aggregate->getBasicType() == EbtUInt);
3220 resultArray[i].setUConst(0);
3221 }
3222 }
3223 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3224 {
3225 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3226 &resultArray[i]);
3227 }
3228 else
3229 {
3230 // bits can be 32 here, so we need to avoid bit shift overflow.
3231 uint32_t maskMsb = 1u << (bits - 1);
3232 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3233 if (aggregate->getBasicType() == EbtInt)
3234 {
3235 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3236 uint32_t resultUnsigned = (value & mask) >> offset;
3237 if ((resultUnsigned & maskMsb) != 0)
3238 {
3239 // The most significant bits (from bits+1 to the most significant bit)
3240 // should be set to 1.
3241 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3242 resultUnsigned |= higherBitsMask;
3243 }
3244 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3245 }
3246 else
3247 {
3248 ASSERT(aggregate->getBasicType() == EbtUInt);
3249 uint32_t value = unionArrays[0][i].getUConst();
3250 resultArray[i].setUConst((value & mask) >> offset);
3251 }
3252 }
3253 }
3254 break;
3255 }
3256 case EOpBitfieldInsert:
3257 {
3258 resultArray = new TConstantUnion[maxObjectSize];
3259 for (size_t i = 0; i < maxObjectSize; ++i)
3260 {
3261 int offset = unionArrays[2][0].getIConst();
3262 int bits = unionArrays[3][0].getIConst();
3263 if (bits == 0)
3264 {
3265 if (aggregate->getBasicType() == EbtInt)
3266 {
3267 int32_t base = unionArrays[0][i].getIConst();
3268 resultArray[i].setIConst(base);
3269 }
3270 else
3271 {
3272 ASSERT(aggregate->getBasicType() == EbtUInt);
3273 uint32_t base = unionArrays[0][i].getUConst();
3274 resultArray[i].setUConst(base);
3275 }
3276 }
3277 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3278 {
3279 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3280 &resultArray[i]);
3281 }
3282 else
3283 {
3284 // bits can be 32 here, so we need to avoid bit shift overflow.
3285 uint32_t maskMsb = 1u << (bits - 1);
3286 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3287 uint32_t baseMask = ~insertMask;
3288 if (aggregate->getBasicType() == EbtInt)
3289 {
3290 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3291 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3292 uint32_t resultUnsigned =
3293 (base & baseMask) | ((insert << offset) & insertMask);
3294 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3295 }
3296 else
3297 {
3298 ASSERT(aggregate->getBasicType() == EbtUInt);
3299 uint32_t base = unionArrays[0][i].getUConst();
3300 uint32_t insert = unionArrays[1][i].getUConst();
3301 resultArray[i].setUConst((base & baseMask) |
3302 ((insert << offset) & insertMask));
3303 }
3304 }
3305 }
3306 break;
3307 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003308
3309 default:
3310 UNREACHABLE();
3311 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303312 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003313 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303314}
3315
Jamie Madill45bcc782016-11-07 13:58:48 -05003316} // namespace sh