blob: 380548502db9175aed8b95cf2c858a13d81eee17 [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 Etuahoea78d2b2018-01-09 12:55:27 +0200525 if (getQualifier() == EvqConst)
526 {
527 return false;
528 }
529 bool calledFunctionHasNoSideEffects =
530 isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects();
531 if (calledFunctionHasNoSideEffects || isConstructor())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300532 {
533 for (TIntermNode *arg : mArguments)
534 {
535 if (arg->getAsTyped()->hasSideEffects())
536 {
537 return true;
538 }
539 }
540 return false;
541 }
542 // Conservatively assume most aggregate operators have side-effects
543 return true;
544}
545
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100546void TIntermBlock::appendStatement(TIntermNode *statement)
547{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300548 // Declaration nodes with no children can appear if it was an empty declaration or if all the
549 // declarators just added constants to the symbol table instead of generating code. We still
550 // need to add the declaration to the AST in that case because it might be relevant to the
551 // validity of switch/case.
552 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100553 {
554 mStatements.push_back(statement);
555 }
556}
557
Olli Etuaho16c745a2017-01-16 17:02:27 +0000558void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
559{
560 ASSERT(parameter != nullptr);
561 mParameters.push_back(parameter);
562}
563
Olli Etuaho13389b62016-10-16 11:48:18 +0100564void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
565{
566 ASSERT(declarator != nullptr);
567 ASSERT(declarator->getAsSymbolNode() != nullptr ||
568 (declarator->getAsBinaryNode() != nullptr &&
569 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
570 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300571 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100572 mDeclarators.push_back(declarator);
573}
574
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300575bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
576{
577 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
578 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
579 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
580 return false;
581}
582
Olli Etuaho57961272016-09-14 13:57:46 +0300583bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400584{
585 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100586 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
587 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400588 return false;
589}
590
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500591bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200592{
593 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100594 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300595 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200596 return false;
597}
598
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500599bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200600{
601 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
602 return false;
603}
604
Olli Etuahod7a25242015-08-18 13:49:45 +0300605TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
606{
607 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
608 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
609 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
610 mLine = node.mLine;
611}
612
Olli Etuahod4f4c112016-04-15 15:11:24 +0300613bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
614{
615 TIntermAggregate *constructor = getAsAggregate();
616 if (!constructor || !constructor->isConstructor())
617 {
618 return false;
619 }
620 for (TIntermNode *&node : *constructor->getSequence())
621 {
622 if (!node->getAsConstantUnion())
623 return false;
624 }
625 return true;
626}
627
Olli Etuahod7a25242015-08-18 13:49:45 +0300628TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
629{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200630 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300631}
632
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200633TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
634 : TIntermTyped(function->getReturnType()), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100635{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200636 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100637}
638
Olli Etuahod7a25242015-08-18 13:49:45 +0300639TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
640 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300641 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100642 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400643 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300644{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800645 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300646 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800647 TIntermTyped *typedArg = arg->getAsTyped();
648 ASSERT(typedArg != nullptr);
649 TIntermTyped *argCopy = typedArg->deepCopy();
650 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300651 }
652}
653
Olli Etuahofe486322017-03-21 09:30:54 +0000654TIntermAggregate *TIntermAggregate::shallowCopy() const
655{
656 TIntermSequence *copySeq = new TIntermSequence();
657 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400658 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000659 copyNode->setLine(mLine);
660 return copyNode;
661}
662
Olli Etuahob6fa0432016-09-28 16:28:05 +0100663TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
664{
665 TIntermTyped *operandCopy = node.mOperand->deepCopy();
666 ASSERT(operandCopy != nullptr);
667 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000668 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100669}
670
Olli Etuahod7a25242015-08-18 13:49:45 +0300671TIntermBinary::TIntermBinary(const TIntermBinary &node)
672 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
673{
674 TIntermTyped *leftCopy = node.mLeft->deepCopy();
675 TIntermTyped *rightCopy = node.mRight->deepCopy();
676 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
677 mLeft = leftCopy;
678 mRight = rightCopy;
679}
680
681TIntermUnary::TIntermUnary(const TIntermUnary &node)
682 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
683{
684 TIntermTyped *operandCopy = node.mOperand->deepCopy();
685 ASSERT(operandCopy != nullptr);
686 mOperand = operandCopy;
687}
688
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300689TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300690{
Olli Etuahod7a25242015-08-18 13:49:45 +0300691 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300692 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
693 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300694 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300695 mCondition = conditionCopy;
696 mTrueExpression = trueCopy;
697 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300698}
699
Jamie Madillb1a85f42014-08-19 15:23:24 -0400700bool TIntermOperator::isAssignment() const
701{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300702 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400703}
704
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300705bool TIntermOperator::isMultiplication() const
706{
707 switch (mOp)
708 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500709 case EOpMul:
710 case EOpMatrixTimesMatrix:
711 case EOpMatrixTimesVector:
712 case EOpMatrixTimesScalar:
713 case EOpVectorTimesMatrix:
714 case EOpVectorTimesScalar:
715 return true;
716 default:
717 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300718 }
719}
720
Jamie Madillb1a85f42014-08-19 15:23:24 -0400721bool TIntermOperator::isConstructor() const
722{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300723 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400724}
725
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800726bool TIntermOperator::isFunctionCall() const
727{
728 switch (mOp)
729 {
730 case EOpCallFunctionInAST:
731 case EOpCallBuiltInFunction:
732 case EOpCallInternalRawFunction:
733 return true;
734 default:
735 return false;
736 }
737}
738
Olli Etuaho1dded802016-08-18 18:13:13 +0300739TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
740{
741 if (left.isMatrix())
742 {
743 if (right.isMatrix())
744 {
745 return EOpMatrixTimesMatrix;
746 }
747 else
748 {
749 if (right.isVector())
750 {
751 return EOpMatrixTimesVector;
752 }
753 else
754 {
755 return EOpMatrixTimesScalar;
756 }
757 }
758 }
759 else
760 {
761 if (right.isMatrix())
762 {
763 if (left.isVector())
764 {
765 return EOpVectorTimesMatrix;
766 }
767 else
768 {
769 return EOpMatrixTimesScalar;
770 }
771 }
772 else
773 {
774 // Neither operand is a matrix.
775 if (left.isVector() == right.isVector())
776 {
777 // Leave as component product.
778 return EOpMul;
779 }
780 else
781 {
782 return EOpVectorTimesScalar;
783 }
784 }
785 }
786}
787
788TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
789{
790 if (left.isMatrix())
791 {
792 if (right.isMatrix())
793 {
794 return EOpMatrixTimesMatrixAssign;
795 }
796 else
797 {
798 // right should be scalar, but this may not be validated yet.
799 return EOpMatrixTimesScalarAssign;
800 }
801 }
802 else
803 {
804 if (right.isMatrix())
805 {
806 // Left should be a vector, but this may not be validated yet.
807 return EOpVectorTimesMatrixAssign;
808 }
809 else
810 {
811 // Neither operand is a matrix.
812 if (left.isVector() == right.isVector())
813 {
814 // Leave as component product.
815 return EOpMulAssign;
816 }
817 else
818 {
819 // left should be vector and right should be scalar, but this may not be validated
820 // yet.
821 return EOpVectorTimesScalarAssign;
822 }
823 }
824 }
825}
826
Jamie Madillb1a85f42014-08-19 15:23:24 -0400827//
828// Make sure the type of a unary operator is appropriate for its
829// combination of operation and operand type.
830//
Olli Etuahoa2234302016-08-31 12:05:39 +0300831void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400832{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300833 if (mOp == EOpArrayLength)
834 {
835 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
836 setType(TType(EbtInt, EbpUndefined, EvqConst));
837 return;
838 }
839
Olli Etuahoa2234302016-08-31 12:05:39 +0300840 TQualifier resultQualifier = EvqTemporary;
841 if (mOperand->getQualifier() == EvqConst)
842 resultQualifier = EvqConst;
843
844 unsigned char operandPrimarySize =
845 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400846 switch (mOp)
847 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300848 case EOpFloatBitsToInt:
849 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
850 break;
851 case EOpFloatBitsToUint:
852 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
853 break;
854 case EOpIntBitsToFloat:
855 case EOpUintBitsToFloat:
856 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
857 break;
858 case EOpPackSnorm2x16:
859 case EOpPackUnorm2x16:
860 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800861 case EOpPackUnorm4x8:
862 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300863 setType(TType(EbtUInt, EbpHigh, resultQualifier));
864 break;
865 case EOpUnpackSnorm2x16:
866 case EOpUnpackUnorm2x16:
867 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
868 break;
869 case EOpUnpackHalf2x16:
870 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
871 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800872 case EOpUnpackUnorm4x8:
873 case EOpUnpackSnorm4x8:
874 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
875 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300876 case EOpAny:
877 case EOpAll:
878 setType(TType(EbtBool, EbpUndefined, resultQualifier));
879 break;
880 case EOpLength:
881 case EOpDeterminant:
882 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
883 break;
884 case EOpTranspose:
885 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
886 static_cast<unsigned char>(mOperand->getType().getRows()),
887 static_cast<unsigned char>(mOperand->getType().getCols())));
888 break;
889 case EOpIsInf:
890 case EOpIsNan:
891 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
892 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000893 case EOpBitfieldReverse:
894 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
895 break;
896 case EOpBitCount:
897 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
898 break;
899 case EOpFindLSB:
900 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
901 break;
902 case EOpFindMSB:
903 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
904 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300905 default:
906 setType(mOperand->getType());
907 mType.setQualifier(resultQualifier);
908 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400909 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300910}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400911
Olli Etuahob6fa0432016-09-28 16:28:05 +0100912TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
913 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
914 mOperand(operand),
915 mSwizzleOffsets(swizzleOffsets)
916{
917 ASSERT(mSwizzleOffsets.size() <= 4);
918 promote();
919}
920
Olli Etuahoa2234302016-08-31 12:05:39 +0300921TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
922 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
923{
924 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400925}
926
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300927TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
928 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
929{
930 promote();
931}
932
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000933TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
934 : TIntermNode(), mSymbol(symbol)
935{
936 ASSERT(symbol);
937 setLine(line);
938}
939
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300940TIntermTernary::TIntermTernary(TIntermTyped *cond,
941 TIntermTyped *trueExpression,
942 TIntermTyped *falseExpression)
943 : TIntermTyped(trueExpression->getType()),
944 mCondition(cond),
945 mTrueExpression(trueExpression),
946 mFalseExpression(falseExpression)
947{
948 getTypePointer()->setQualifier(
949 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
950}
951
Olli Etuaho81629262017-04-19 11:56:01 +0300952TIntermLoop::TIntermLoop(TLoopType type,
953 TIntermNode *init,
954 TIntermTyped *cond,
955 TIntermTyped *expr,
956 TIntermBlock *body)
957 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
958{
959 // Declaration nodes with no children can appear if all the declarators just added constants to
960 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
961 if (mInit && mInit->getAsDeclarationNode() &&
962 mInit->getAsDeclarationNode()->getSequence()->empty())
963 {
964 mInit = nullptr;
965 }
966}
967
Olli Etuaho923ecef2017-10-11 12:01:38 +0300968TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
969 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
970{
971 // Prune empty false blocks so that there won't be unnecessary operations done on it.
972 if (mFalseBlock && mFalseBlock->getSequence()->empty())
973 {
974 mFalseBlock = nullptr;
975 }
976}
977
978TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
979 : TIntermNode(), mInit(init), mStatementList(statementList)
980{
981 ASSERT(mStatementList);
982}
983
984void TIntermSwitch::setStatementList(TIntermBlock *statementList)
985{
986 ASSERT(statementList);
987 mStatementList = statementList;
988}
989
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300990// static
991TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
992 TIntermTyped *trueExpression,
993 TIntermTyped *falseExpression)
994{
995 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
996 falseExpression->getQualifier() == EvqConst)
997 {
998 return EvqConst;
999 }
1000 return EvqTemporary;
1001}
1002
Olli Etuaho765924f2018-01-04 12:48:36 +02001003TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001004{
1005 if (mCondition->getAsConstantUnion())
1006 {
1007 if (mCondition->getAsConstantUnion()->getBConst(0))
1008 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001009 return mTrueExpression;
1010 }
1011 else
1012 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001013 return mFalseExpression;
1014 }
1015 }
1016 return this;
1017}
1018
Olli Etuahob6fa0432016-09-28 16:28:05 +01001019void TIntermSwizzle::promote()
1020{
1021 TQualifier resultQualifier = EvqTemporary;
1022 if (mOperand->getQualifier() == EvqConst)
1023 resultQualifier = EvqConst;
1024
1025 auto numFields = mSwizzleOffsets.size();
1026 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1027 static_cast<unsigned char>(numFields)));
1028}
1029
1030bool TIntermSwizzle::hasDuplicateOffsets() const
1031{
1032 int offsetCount[4] = {0u, 0u, 0u, 0u};
1033 for (const auto offset : mSwizzleOffsets)
1034 {
1035 offsetCount[offset]++;
1036 if (offsetCount[offset] > 1)
1037 {
1038 return true;
1039 }
1040 }
1041 return false;
1042}
1043
Olli Etuaho09b04a22016-12-15 13:30:26 +00001044bool TIntermSwizzle::offsetsMatch(int offset) const
1045{
1046 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1047}
1048
Olli Etuahob6fa0432016-09-28 16:28:05 +01001049void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1050{
1051 for (const int offset : mSwizzleOffsets)
1052 {
1053 switch (offset)
1054 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001055 case 0:
1056 *out << "x";
1057 break;
1058 case 1:
1059 *out << "y";
1060 break;
1061 case 2:
1062 *out << "z";
1063 break;
1064 case 3:
1065 *out << "w";
1066 break;
1067 default:
1068 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001069 }
1070 }
1071}
1072
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001073TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1074 const TIntermTyped *left,
1075 const TIntermTyped *right)
1076{
1077 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1078 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1079 right->getQualifier() != EvqConst)
1080 {
1081 return EvqTemporary;
1082 }
1083 return EvqConst;
1084}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001085
1086// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001087void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001088{
Olli Etuaho1dded802016-08-18 18:13:13 +03001089 ASSERT(!isMultiplication() ||
1090 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1091
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001092 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1093 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001094 if (mOp == EOpComma)
1095 {
1096 setType(mRight->getType());
1097 return;
1098 }
1099
Jamie Madillb1a85f42014-08-19 15:23:24 -04001100 // Base assumption: just make the type the same as the left
1101 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001102 setType(mLeft->getType());
1103
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001104 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001105 // Binary operations results in temporary variables unless both
1106 // operands are const.
1107 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1108 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001109 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001110 getTypePointer()->setQualifier(EvqTemporary);
1111 }
1112
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001113 // Handle indexing ops.
1114 switch (mOp)
1115 {
1116 case EOpIndexDirect:
1117 case EOpIndexIndirect:
1118 if (mLeft->isArray())
1119 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001120 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001121 }
1122 else if (mLeft->isMatrix())
1123 {
1124 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1125 static_cast<unsigned char>(mLeft->getRows())));
1126 }
1127 else if (mLeft->isVector())
1128 {
1129 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1130 }
1131 else
1132 {
1133 UNREACHABLE();
1134 }
1135 return;
1136 case EOpIndexDirectStruct:
1137 {
1138 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1139 const int i = mRight->getAsConstantUnion()->getIConst(0);
1140 setType(*fields[i]->type());
1141 getTypePointer()->setQualifier(resultQualifier);
1142 return;
1143 }
1144 case EOpIndexDirectInterfaceBlock:
1145 {
1146 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1147 const int i = mRight->getAsConstantUnion()->getIConst(0);
1148 setType(*fields[i]->type());
1149 getTypePointer()->setQualifier(resultQualifier);
1150 return;
1151 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001152 default:
1153 break;
1154 }
1155
1156 ASSERT(mLeft->isArray() == mRight->isArray());
1157
1158 // The result gets promoted to the highest precision.
1159 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1160 getTypePointer()->setPrecision(higherPrecision);
1161
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001162 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001163
1164 //
1165 // All scalars or structs. Code after this test assumes this case is removed!
1166 //
1167 if (nominalSize == 1)
1168 {
1169 switch (mOp)
1170 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001171 //
1172 // Promote to conditional
1173 //
1174 case EOpEqual:
1175 case EOpNotEqual:
1176 case EOpLessThan:
1177 case EOpGreaterThan:
1178 case EOpLessThanEqual:
1179 case EOpGreaterThanEqual:
1180 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1181 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001182
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001183 //
1184 // And and Or operate on conditionals
1185 //
1186 case EOpLogicalAnd:
1187 case EOpLogicalXor:
1188 case EOpLogicalOr:
1189 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1190 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1191 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001192
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001193 default:
1194 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001195 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001196 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001197 }
1198
1199 // If we reach here, at least one of the operands is vector or matrix.
1200 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001201 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001202
Jamie Madillb1a85f42014-08-19 15:23:24 -04001203 switch (mOp)
1204 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001205 case EOpMul:
1206 break;
1207 case EOpMatrixTimesScalar:
1208 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001209 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001210 setType(TType(basicType, higherPrecision, resultQualifier,
1211 static_cast<unsigned char>(mRight->getCols()),
1212 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001213 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001214 break;
1215 case EOpMatrixTimesVector:
1216 setType(TType(basicType, higherPrecision, resultQualifier,
1217 static_cast<unsigned char>(mLeft->getRows()), 1));
1218 break;
1219 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001220 setType(TType(basicType, higherPrecision, resultQualifier,
1221 static_cast<unsigned char>(mRight->getCols()),
1222 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001223 break;
1224 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001225 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001226 static_cast<unsigned char>(nominalSize), 1));
1227 break;
1228 case EOpVectorTimesMatrix:
1229 setType(TType(basicType, higherPrecision, resultQualifier,
1230 static_cast<unsigned char>(mRight->getCols()), 1));
1231 break;
1232 case EOpMulAssign:
1233 case EOpVectorTimesScalarAssign:
1234 case EOpVectorTimesMatrixAssign:
1235 case EOpMatrixTimesScalarAssign:
1236 case EOpMatrixTimesMatrixAssign:
1237 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1238 break;
1239 case EOpAssign:
1240 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001241 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1242 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1243 break;
1244 case EOpAdd:
1245 case EOpSub:
1246 case EOpDiv:
1247 case EOpIMod:
1248 case EOpBitShiftLeft:
1249 case EOpBitShiftRight:
1250 case EOpBitwiseAnd:
1251 case EOpBitwiseXor:
1252 case EOpBitwiseOr:
1253 case EOpAddAssign:
1254 case EOpSubAssign:
1255 case EOpDivAssign:
1256 case EOpIModAssign:
1257 case EOpBitShiftLeftAssign:
1258 case EOpBitShiftRightAssign:
1259 case EOpBitwiseAndAssign:
1260 case EOpBitwiseXorAssign:
1261 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001262 {
1263 const int secondarySize =
1264 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1265 setType(TType(basicType, higherPrecision, resultQualifier,
1266 static_cast<unsigned char>(nominalSize),
1267 static_cast<unsigned char>(secondarySize)));
1268 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001269 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001270 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001271 case EOpEqual:
1272 case EOpNotEqual:
1273 case EOpLessThan:
1274 case EOpGreaterThan:
1275 case EOpLessThanEqual:
1276 case EOpGreaterThanEqual:
1277 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1278 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001279 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001280 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001281
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001282 case EOpIndexDirect:
1283 case EOpIndexIndirect:
1284 case EOpIndexDirectInterfaceBlock:
1285 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001286 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001287 UNREACHABLE();
1288 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001289 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001290 UNREACHABLE();
1291 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001292 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001293}
1294
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001295const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001296{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001297 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001298 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001299 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001300 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001301 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001302 size_t arrayElementSize = arrayElementType.getObjectSize();
1303 return &mUnionArrayPointer[arrayElementSize * index];
1304 }
1305 else if (isMatrix())
1306 {
1307 ASSERT(index < getType().getCols());
1308 int size = getType().getRows();
1309 return &mUnionArrayPointer[size * index];
1310 }
1311 else if (isVector())
1312 {
1313 ASSERT(index < getType().getNominalSize());
1314 return &mUnionArrayPointer[index];
1315 }
1316 else
1317 {
1318 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001319 return nullptr;
1320 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001321}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001322
Olli Etuaho765924f2018-01-04 12:48:36 +02001323TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001324{
1325 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1326 if (operandConstant == nullptr)
1327 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001328 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001329 }
1330
1331 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1332 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1333 {
1334 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1335 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001336 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001337}
1338
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001339TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1340{
1341 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1342 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1343 switch (mOp)
1344 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001345 case EOpComma:
1346 {
1347 if (mLeft->hasSideEffects())
1348 {
1349 return this;
1350 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001351 return mRight;
1352 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001353 case EOpIndexDirect:
1354 {
1355 if (leftConstant == nullptr || rightConstant == nullptr)
1356 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001357 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001358 }
1359 int index = rightConstant->getIConst(0);
1360
1361 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001362 if (!constArray)
1363 {
1364 return this;
1365 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001366 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001367 }
1368 case EOpIndexDirectStruct:
1369 {
1370 if (leftConstant == nullptr || rightConstant == nullptr)
1371 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001372 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001373 }
1374 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1375 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1376
1377 size_t previousFieldsSize = 0;
1378 for (size_t i = 0; i < index; ++i)
1379 {
1380 previousFieldsSize += fields[i]->type()->getObjectSize();
1381 }
1382
1383 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
Olli Etuaho2768bc82017-12-12 11:51:48 +02001384 return CreateFoldedNode(constArray + previousFieldsSize, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001385 }
1386 case EOpIndexIndirect:
1387 case EOpIndexDirectInterfaceBlock:
1388 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001389 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001390 default:
1391 {
1392 if (leftConstant == nullptr || rightConstant == nullptr)
1393 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001394 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001395 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001396 TConstantUnion *constArray =
1397 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001398 if (!constArray)
1399 {
1400 return this;
1401 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001402 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001403 }
1404 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001405}
1406
Olli Etuahof119a262016-08-19 15:54:22 +03001407TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001408{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301409 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001410
1411 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301412 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001413 // The size of runtime-sized arrays may only be determined at runtime.
1414 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001415 {
1416 return this;
1417 }
1418 constArray = new TConstantUnion[1];
1419 constArray->setIConst(mOperand->getOutermostArraySize());
1420 }
1421 else
1422 {
1423 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1424 if (operandConstant == nullptr)
1425 {
1426 return this;
1427 }
1428
1429 switch (mOp)
1430 {
1431 case EOpAny:
1432 case EOpAll:
1433 case EOpLength:
1434 case EOpTranspose:
1435 case EOpDeterminant:
1436 case EOpInverse:
1437 case EOpPackSnorm2x16:
1438 case EOpUnpackSnorm2x16:
1439 case EOpPackUnorm2x16:
1440 case EOpUnpackUnorm2x16:
1441 case EOpPackHalf2x16:
1442 case EOpUnpackHalf2x16:
1443 case EOpPackUnorm4x8:
1444 case EOpPackSnorm4x8:
1445 case EOpUnpackUnorm4x8:
1446 case EOpUnpackSnorm4x8:
1447 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1448 break;
1449 default:
1450 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1451 break;
1452 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301453 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001454 if (constArray == nullptr)
1455 {
1456 return this;
1457 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001458 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001459}
1460
Olli Etuahof119a262016-08-19 15:54:22 +03001461TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001462{
1463 // Make sure that all params are constant before actual constant folding.
1464 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001465 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001466 if (param->getAsConstantUnion() == nullptr)
1467 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001468 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001469 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001470 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001471 TConstantUnion *constArray = nullptr;
1472 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001473 {
Olli Etuaho765924f2018-01-04 12:48:36 +02001474 // TODO(oetuaho@nvidia.com): Add support for folding array constructors.
1475 if (!isArray())
1476 {
1477 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
1478 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001479 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001480 else if (CanFoldAggregateBuiltInOp(mOp))
Olli Etuaho2768bc82017-12-12 11:51:48 +02001481 {
Olli Etuahof119a262016-08-19 15:54:22 +03001482 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001483 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001484 if (constArray == nullptr)
1485 {
1486 return this;
1487 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001488 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001489}
1490
Jamie Madillb1a85f42014-08-19 15:23:24 -04001491//
1492// The fold functions see if an operation on a constant can be done in place,
1493// without generating run-time code.
1494//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001495// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001496//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001497TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1498 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001499 TDiagnostics *diagnostics,
1500 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001501{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001502 const TConstantUnion *leftArray = getUnionArrayPointer();
1503 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001504
Olli Etuahof119a262016-08-19 15:54:22 +03001505 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001506
1507 size_t objectSize = getType().getObjectSize();
1508
1509 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1510 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1511 {
1512 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1513 }
1514 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1515 {
1516 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001517 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001518 objectSize = rightNode->getType().getObjectSize();
1519 }
1520
1521 TConstantUnion *resultArray = nullptr;
1522
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001523 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001524 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001525 case EOpAdd:
1526 resultArray = new TConstantUnion[objectSize];
1527 for (size_t i = 0; i < objectSize; i++)
1528 resultArray[i] =
1529 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1530 break;
1531 case EOpSub:
1532 resultArray = new TConstantUnion[objectSize];
1533 for (size_t i = 0; i < objectSize; i++)
1534 resultArray[i] =
1535 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1536 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001537
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001538 case EOpMul:
1539 case EOpVectorTimesScalar:
1540 case EOpMatrixTimesScalar:
1541 resultArray = new TConstantUnion[objectSize];
1542 for (size_t i = 0; i < objectSize; i++)
1543 resultArray[i] =
1544 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1545 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001546
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001547 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001548 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001549 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001550 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001551
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001552 const int leftCols = getCols();
1553 const int leftRows = getRows();
1554 const int rightCols = rightNode->getType().getCols();
1555 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001556 const int resultCols = rightCols;
1557 const int resultRows = leftRows;
1558
1559 resultArray = new TConstantUnion[resultCols * resultRows];
1560 for (int row = 0; row < resultRows; row++)
1561 {
1562 for (int column = 0; column < resultCols; column++)
1563 {
1564 resultArray[resultRows * column + row].setFConst(0.0f);
1565 for (int i = 0; i < leftCols; i++)
1566 {
1567 resultArray[resultRows * column + row].setFConst(
1568 resultArray[resultRows * column + row].getFConst() +
1569 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001570 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001571 }
1572 }
1573 }
1574 }
1575 break;
1576
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001577 case EOpDiv:
1578 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001579 {
1580 resultArray = new TConstantUnion[objectSize];
1581 for (size_t i = 0; i < objectSize; i++)
1582 {
1583 switch (getType().getBasicType())
1584 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001585 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001586 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001587 ASSERT(op == EOpDiv);
1588 float dividend = leftArray[i].getFConst();
1589 float divisor = rightArray[i].getFConst();
1590 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001591 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001592 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001593 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001594 diagnostics->warning(
1595 getLine(),
1596 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001597 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001598 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001599 }
1600 else
1601 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001602 diagnostics->warning(getLine(),
1603 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001604 bool negativeResult =
1605 std::signbit(dividend) != std::signbit(divisor);
1606 resultArray[i].setFConst(
1607 negativeResult ? -std::numeric_limits<float>::infinity()
1608 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001609 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001610 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001611 else if (gl::isInf(dividend) && gl::isInf(divisor))
1612 {
1613 diagnostics->warning(getLine(),
1614 "Infinity divided by infinity during constant "
1615 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001616 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001617 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1618 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001619 else
1620 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001621 float result = dividend / divisor;
1622 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001623 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001624 diagnostics->warning(
1625 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001626 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001627 }
1628 resultArray[i].setFConst(result);
1629 }
1630 break;
1631 }
1632 case EbtInt:
1633 if (rightArray[i] == 0)
1634 {
1635 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001636 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001637 resultArray[i].setIConst(INT_MAX);
1638 }
1639 else
1640 {
1641 int lhs = leftArray[i].getIConst();
1642 int divisor = rightArray[i].getIConst();
1643 if (op == EOpDiv)
1644 {
1645 // Check for the special case where the minimum representable number
1646 // is
1647 // divided by -1. If left alone this leads to integer overflow in
1648 // C++.
1649 // ESSL 3.00.6 section 4.1.3 Integers:
1650 // "However, for the case where the minimum representable value is
1651 // divided by -1, it is allowed to return either the minimum
1652 // representable value or the maximum representable value."
1653 if (lhs == -0x7fffffff - 1 && divisor == -1)
1654 {
1655 resultArray[i].setIConst(0x7fffffff);
1656 }
1657 else
1658 {
1659 resultArray[i].setIConst(lhs / divisor);
1660 }
Olli Etuahod4453572016-09-27 13:21:46 +01001661 }
1662 else
1663 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001664 ASSERT(op == EOpIMod);
1665 if (lhs < 0 || divisor < 0)
1666 {
1667 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1668 // when
1669 // either one of the operands is negative.
1670 diagnostics->warning(getLine(),
1671 "Negative modulus operator operand "
1672 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001673 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001674 resultArray[i].setIConst(0);
1675 }
1676 else
1677 {
1678 resultArray[i].setIConst(lhs % divisor);
1679 }
Olli Etuahod4453572016-09-27 13:21:46 +01001680 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001681 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001682 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001683
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001684 case EbtUInt:
1685 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001686 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001687 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001688 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001689 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001690 }
1691 else
1692 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001693 if (op == EOpDiv)
1694 {
1695 resultArray[i].setUConst(leftArray[i].getUConst() /
1696 rightArray[i].getUConst());
1697 }
1698 else
1699 {
1700 ASSERT(op == EOpIMod);
1701 resultArray[i].setUConst(leftArray[i].getUConst() %
1702 rightArray[i].getUConst());
1703 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001704 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001705 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001706
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001707 default:
1708 UNREACHABLE();
1709 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001710 }
1711 }
1712 }
1713 break;
1714
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001715 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001716 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001717 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001718 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001719
1720 const int matrixCols = getCols();
1721 const int matrixRows = getRows();
1722
1723 resultArray = new TConstantUnion[matrixRows];
1724
1725 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1726 {
1727 resultArray[matrixRow].setFConst(0.0f);
1728 for (int col = 0; col < matrixCols; col++)
1729 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001730 resultArray[matrixRow].setFConst(
1731 resultArray[matrixRow].getFConst() +
1732 leftArray[col * matrixRows + matrixRow].getFConst() *
1733 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001734 }
1735 }
1736 }
1737 break;
1738
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001739 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001740 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001741 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001742 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001743
1744 const int matrixCols = rightNode->getType().getCols();
1745 const int matrixRows = rightNode->getType().getRows();
1746
1747 resultArray = new TConstantUnion[matrixCols];
1748
1749 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1750 {
1751 resultArray[matrixCol].setFConst(0.0f);
1752 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1753 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001754 resultArray[matrixCol].setFConst(
1755 resultArray[matrixCol].getFConst() +
1756 leftArray[matrixRow].getFConst() *
1757 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001758 }
1759 }
1760 }
1761 break;
1762
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001763 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001764 {
1765 resultArray = new TConstantUnion[objectSize];
1766 for (size_t i = 0; i < objectSize; i++)
1767 {
1768 resultArray[i] = leftArray[i] && rightArray[i];
1769 }
1770 }
1771 break;
1772
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001773 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001774 {
1775 resultArray = new TConstantUnion[objectSize];
1776 for (size_t i = 0; i < objectSize; i++)
1777 {
1778 resultArray[i] = leftArray[i] || rightArray[i];
1779 }
1780 }
1781 break;
1782
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001783 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001784 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001785 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001786 resultArray = new TConstantUnion[objectSize];
1787 for (size_t i = 0; i < objectSize; i++)
1788 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001789 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001790 }
1791 }
1792 break;
1793
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001794 case EOpBitwiseAnd:
1795 resultArray = new TConstantUnion[objectSize];
1796 for (size_t i = 0; i < objectSize; i++)
1797 resultArray[i] = leftArray[i] & rightArray[i];
1798 break;
1799 case EOpBitwiseXor:
1800 resultArray = new TConstantUnion[objectSize];
1801 for (size_t i = 0; i < objectSize; i++)
1802 resultArray[i] = leftArray[i] ^ rightArray[i];
1803 break;
1804 case EOpBitwiseOr:
1805 resultArray = new TConstantUnion[objectSize];
1806 for (size_t i = 0; i < objectSize; i++)
1807 resultArray[i] = leftArray[i] | rightArray[i];
1808 break;
1809 case EOpBitShiftLeft:
1810 resultArray = new TConstantUnion[objectSize];
1811 for (size_t i = 0; i < objectSize; i++)
1812 resultArray[i] =
1813 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1814 break;
1815 case EOpBitShiftRight:
1816 resultArray = new TConstantUnion[objectSize];
1817 for (size_t i = 0; i < objectSize; i++)
1818 resultArray[i] =
1819 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1820 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001821
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001822 case EOpLessThan:
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 EOpGreaterThan:
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 EOpLessThanEqual:
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 EOpGreaterThanEqual:
1841 ASSERT(objectSize == 1);
1842 resultArray = new TConstantUnion[1];
1843 resultArray->setBConst(!(*leftArray < *rightArray));
1844 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001845
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001846 case EOpEqual:
1847 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001848 {
1849 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001850 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001851 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001852 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001853 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001854 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001855 equal = false;
1856 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001857 }
1858 }
1859 if (op == EOpEqual)
1860 {
1861 resultArray->setBConst(equal);
1862 }
1863 else
1864 {
1865 resultArray->setBConst(!equal);
1866 }
1867 }
1868 break;
1869
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001870 default:
1871 UNREACHABLE();
1872 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001873 }
1874 return resultArray;
1875}
1876
Olli Etuahof119a262016-08-19 15:54:22 +03001877// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1878// code. Returns the constant value to keep using. Nullptr should not be returned.
1879TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001880{
Olli Etuahof119a262016-08-19 15:54:22 +03001881 // Do operations where the return type may have a different number of components compared to the
1882 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001883
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001884 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001885 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301886
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001887 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301888 TConstantUnion *resultArray = nullptr;
1889 switch (op)
1890 {
Olli Etuahof119a262016-08-19 15:54:22 +03001891 case EOpAny:
1892 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301893 resultArray = new TConstantUnion();
1894 resultArray->setBConst(false);
1895 for (size_t i = 0; i < objectSize; i++)
1896 {
1897 if (operandArray[i].getBConst())
1898 {
1899 resultArray->setBConst(true);
1900 break;
1901 }
1902 }
1903 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301904
Olli Etuahof119a262016-08-19 15:54:22 +03001905 case EOpAll:
1906 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301907 resultArray = new TConstantUnion();
1908 resultArray->setBConst(true);
1909 for (size_t i = 0; i < objectSize; i++)
1910 {
1911 if (!operandArray[i].getBConst())
1912 {
1913 resultArray->setBConst(false);
1914 break;
1915 }
1916 }
1917 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301918
Olli Etuahof119a262016-08-19 15:54:22 +03001919 case EOpLength:
1920 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301921 resultArray = new TConstantUnion();
1922 resultArray->setFConst(VectorLength(operandArray, objectSize));
1923 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301924
Olli Etuahof119a262016-08-19 15:54:22 +03001925 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301926 {
Olli Etuahof119a262016-08-19 15:54:22 +03001927 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301928 resultArray = new TConstantUnion[objectSize];
1929 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001930 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301931 SetUnionArrayFromMatrix(result, resultArray);
1932 break;
1933 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301934
Olli Etuahof119a262016-08-19 15:54:22 +03001935 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301936 {
Olli Etuahof119a262016-08-19 15:54:22 +03001937 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301938 unsigned int size = getType().getNominalSize();
1939 ASSERT(size >= 2 && size <= 4);
1940 resultArray = new TConstantUnion();
1941 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1942 break;
1943 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301944
Olli Etuahof119a262016-08-19 15:54:22 +03001945 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301946 {
Olli Etuahof119a262016-08-19 15:54:22 +03001947 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301948 unsigned int size = getType().getNominalSize();
1949 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001950 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301951 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1952 SetUnionArrayFromMatrix(result, resultArray);
1953 break;
1954 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301955
Olli Etuahof119a262016-08-19 15:54:22 +03001956 case EOpPackSnorm2x16:
1957 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301958 ASSERT(getType().getNominalSize() == 2);
1959 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001960 resultArray->setUConst(
1961 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301962 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301963
Olli Etuahof119a262016-08-19 15:54:22 +03001964 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301965 {
Olli Etuahof119a262016-08-19 15:54:22 +03001966 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301967 resultArray = new TConstantUnion[2];
1968 float f1, f2;
1969 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1970 resultArray[0].setFConst(f1);
1971 resultArray[1].setFConst(f2);
1972 break;
1973 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301974
Olli Etuahof119a262016-08-19 15:54:22 +03001975 case EOpPackUnorm2x16:
1976 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301977 ASSERT(getType().getNominalSize() == 2);
1978 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001979 resultArray->setUConst(
1980 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301981 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301982
Olli Etuahof119a262016-08-19 15:54:22 +03001983 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301984 {
Olli Etuahof119a262016-08-19 15:54:22 +03001985 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301986 resultArray = new TConstantUnion[2];
1987 float f1, f2;
1988 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1989 resultArray[0].setFConst(f1);
1990 resultArray[1].setFConst(f2);
1991 break;
1992 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301993
Olli Etuahof119a262016-08-19 15:54:22 +03001994 case EOpPackHalf2x16:
1995 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301996 ASSERT(getType().getNominalSize() == 2);
1997 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001998 resultArray->setUConst(
1999 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302000 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302001
Olli Etuahof119a262016-08-19 15:54:22 +03002002 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302003 {
Olli Etuahof119a262016-08-19 15:54:22 +03002004 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302005 resultArray = new TConstantUnion[2];
2006 float f1, f2;
2007 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2008 resultArray[0].setFConst(f1);
2009 resultArray[1].setFConst(f2);
2010 break;
2011 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302012
Olli Etuaho25aef452017-01-29 16:15:44 -08002013 case EOpPackUnorm4x8:
2014 {
2015 ASSERT(getType().getBasicType() == EbtFloat);
2016 resultArray = new TConstantUnion();
2017 resultArray->setUConst(
2018 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2019 operandArray[2].getFConst(), operandArray[3].getFConst()));
2020 break;
2021 }
2022 case EOpPackSnorm4x8:
2023 {
2024 ASSERT(getType().getBasicType() == EbtFloat);
2025 resultArray = new TConstantUnion();
2026 resultArray->setUConst(
2027 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2028 operandArray[2].getFConst(), operandArray[3].getFConst()));
2029 break;
2030 }
2031 case EOpUnpackUnorm4x8:
2032 {
2033 ASSERT(getType().getBasicType() == EbtUInt);
2034 resultArray = new TConstantUnion[4];
2035 float f[4];
2036 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2037 for (size_t i = 0; i < 4; ++i)
2038 {
2039 resultArray[i].setFConst(f[i]);
2040 }
2041 break;
2042 }
2043 case EOpUnpackSnorm4x8:
2044 {
2045 ASSERT(getType().getBasicType() == EbtUInt);
2046 resultArray = new TConstantUnion[4];
2047 float f[4];
2048 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2049 for (size_t i = 0; i < 4; ++i)
2050 {
2051 resultArray[i].setFConst(f[i]);
2052 }
2053 break;
2054 }
2055
Olli Etuahof119a262016-08-19 15:54:22 +03002056 default:
2057 UNREACHABLE();
2058 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302059 }
2060
2061 return resultArray;
2062}
2063
Olli Etuahof119a262016-08-19 15:54:22 +03002064TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2065 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302066{
Olli Etuahof119a262016-08-19 15:54:22 +03002067 // Do unary operations where each component of the result is computed based on the corresponding
2068 // component of the operand. Also folds normalize, though the divisor in that case takes all
2069 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302070
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002071 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002072 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002073
2074 size_t objectSize = getType().getObjectSize();
2075
Arun Patoleab2b9a22015-07-06 18:27:56 +05302076 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2077 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302078 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002079 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302080 {
Olli Etuahof119a262016-08-19 15:54:22 +03002081 case EOpNegative:
2082 switch (getType().getBasicType())
2083 {
2084 case EbtFloat:
2085 resultArray[i].setFConst(-operandArray[i].getFConst());
2086 break;
2087 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002088 if (operandArray[i] == std::numeric_limits<int>::min())
2089 {
2090 // The minimum representable integer doesn't have a positive
2091 // counterpart, rather the negation overflows and in ESSL is supposed to
2092 // wrap back to the minimum representable integer. Make sure that we
2093 // don't actually let the negation overflow, which has undefined
2094 // behavior in C++.
2095 resultArray[i].setIConst(std::numeric_limits<int>::min());
2096 }
2097 else
2098 {
2099 resultArray[i].setIConst(-operandArray[i].getIConst());
2100 }
Olli Etuahof119a262016-08-19 15:54:22 +03002101 break;
2102 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002103 if (operandArray[i] == 0x80000000u)
2104 {
2105 resultArray[i].setUConst(0x80000000u);
2106 }
2107 else
2108 {
2109 resultArray[i].setUConst(static_cast<unsigned int>(
2110 -static_cast<int>(operandArray[i].getUConst())));
2111 }
Olli Etuahof119a262016-08-19 15:54:22 +03002112 break;
2113 default:
2114 UNREACHABLE();
2115 return nullptr;
2116 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302117 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302118
Olli Etuahof119a262016-08-19 15:54:22 +03002119 case EOpPositive:
2120 switch (getType().getBasicType())
2121 {
2122 case EbtFloat:
2123 resultArray[i].setFConst(operandArray[i].getFConst());
2124 break;
2125 case EbtInt:
2126 resultArray[i].setIConst(operandArray[i].getIConst());
2127 break;
2128 case EbtUInt:
2129 resultArray[i].setUConst(static_cast<unsigned int>(
2130 static_cast<int>(operandArray[i].getUConst())));
2131 break;
2132 default:
2133 UNREACHABLE();
2134 return nullptr;
2135 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302137
Olli Etuahof119a262016-08-19 15:54:22 +03002138 case EOpLogicalNot:
2139 switch (getType().getBasicType())
2140 {
2141 case EbtBool:
2142 resultArray[i].setBConst(!operandArray[i].getBConst());
2143 break;
2144 default:
2145 UNREACHABLE();
2146 return nullptr;
2147 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302148 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302149
Olli Etuahof119a262016-08-19 15:54:22 +03002150 case EOpBitwiseNot:
2151 switch (getType().getBasicType())
2152 {
2153 case EbtInt:
2154 resultArray[i].setIConst(~operandArray[i].getIConst());
2155 break;
2156 case EbtUInt:
2157 resultArray[i].setUConst(~operandArray[i].getUConst());
2158 break;
2159 default:
2160 UNREACHABLE();
2161 return nullptr;
2162 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302163 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302164
Olli Etuahof119a262016-08-19 15:54:22 +03002165 case EOpRadians:
2166 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302167 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2168 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302169
Olli Etuahof119a262016-08-19 15:54:22 +03002170 case EOpDegrees:
2171 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302172 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2173 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302174
Olli Etuahof119a262016-08-19 15:54:22 +03002175 case EOpSin:
2176 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302177 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302178
Olli Etuahof119a262016-08-19 15:54:22 +03002179 case EOpCos:
2180 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2181 break;
2182
2183 case EOpTan:
2184 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2185 break;
2186
2187 case EOpAsin:
2188 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2189 // 0.
2190 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2191 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2192 diagnostics, &resultArray[i]);
2193 else
2194 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2195 break;
2196
2197 case EOpAcos:
2198 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2199 // 0.
2200 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2201 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2202 diagnostics, &resultArray[i]);
2203 else
2204 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2205 break;
2206
2207 case EOpAtan:
2208 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2209 break;
2210
2211 case EOpSinh:
2212 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2213 break;
2214
2215 case EOpCosh:
2216 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2217 break;
2218
2219 case EOpTanh:
2220 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2221 break;
2222
2223 case EOpAsinh:
2224 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2225 break;
2226
2227 case EOpAcosh:
2228 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2229 if (operandArray[i].getFConst() < 1.0f)
2230 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2231 diagnostics, &resultArray[i]);
2232 else
2233 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2234 break;
2235
2236 case EOpAtanh:
2237 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2238 // 0.
2239 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2240 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2241 diagnostics, &resultArray[i]);
2242 else
2243 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2244 break;
2245
2246 case EOpAbs:
2247 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302248 {
Olli Etuahof119a262016-08-19 15:54:22 +03002249 case EbtFloat:
2250 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2251 break;
2252 case EbtInt:
2253 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2254 break;
2255 default:
2256 UNREACHABLE();
2257 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302258 }
2259 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002260
2261 case EOpSign:
2262 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302263 {
Olli Etuahof119a262016-08-19 15:54:22 +03002264 case EbtFloat:
2265 {
2266 float fConst = operandArray[i].getFConst();
2267 float fResult = 0.0f;
2268 if (fConst > 0.0f)
2269 fResult = 1.0f;
2270 else if (fConst < 0.0f)
2271 fResult = -1.0f;
2272 resultArray[i].setFConst(fResult);
2273 break;
2274 }
2275 case EbtInt:
2276 {
2277 int iConst = operandArray[i].getIConst();
2278 int iResult = 0;
2279 if (iConst > 0)
2280 iResult = 1;
2281 else if (iConst < 0)
2282 iResult = -1;
2283 resultArray[i].setIConst(iResult);
2284 break;
2285 }
2286 default:
2287 UNREACHABLE();
2288 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302289 }
2290 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302291
Olli Etuahof119a262016-08-19 15:54:22 +03002292 case EOpFloor:
2293 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2294 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302295
Olli Etuahof119a262016-08-19 15:54:22 +03002296 case EOpTrunc:
2297 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2298 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302299
Olli Etuahof119a262016-08-19 15:54:22 +03002300 case EOpRound:
2301 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2302 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302303
Olli Etuahof119a262016-08-19 15:54:22 +03002304 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302305 {
Olli Etuahof119a262016-08-19 15:54:22 +03002306 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302307 float x = operandArray[i].getFConst();
2308 float result;
2309 float fractPart = modff(x, &result);
2310 if (fabsf(fractPart) == 0.5f)
2311 result = 2.0f * roundf(x / 2.0f);
2312 else
2313 result = roundf(x);
2314 resultArray[i].setFConst(result);
2315 break;
2316 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302317
Olli Etuahof119a262016-08-19 15:54:22 +03002318 case EOpCeil:
2319 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2320 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302321
Olli Etuahof119a262016-08-19 15:54:22 +03002322 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302323 {
Olli Etuahof119a262016-08-19 15:54:22 +03002324 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302325 float x = operandArray[i].getFConst();
2326 resultArray[i].setFConst(x - floorf(x));
2327 break;
2328 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302329
Olli Etuahof119a262016-08-19 15:54:22 +03002330 case EOpIsNan:
2331 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302332 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2333 break;
Arun Patole551279e2015-07-07 18:18:23 +05302334
Olli Etuahof119a262016-08-19 15:54:22 +03002335 case EOpIsInf:
2336 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302337 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2338 break;
Arun Patole551279e2015-07-07 18:18:23 +05302339
Olli Etuahof119a262016-08-19 15:54:22 +03002340 case EOpFloatBitsToInt:
2341 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302342 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2343 break;
Arun Patole551279e2015-07-07 18:18:23 +05302344
Olli Etuahof119a262016-08-19 15:54:22 +03002345 case EOpFloatBitsToUint:
2346 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302347 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2348 break;
Arun Patole551279e2015-07-07 18:18:23 +05302349
Olli Etuahof119a262016-08-19 15:54:22 +03002350 case EOpIntBitsToFloat:
2351 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302352 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2353 break;
Arun Patole551279e2015-07-07 18:18:23 +05302354
Olli Etuahof119a262016-08-19 15:54:22 +03002355 case EOpUintBitsToFloat:
2356 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302357 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2358 break;
Arun Patole551279e2015-07-07 18:18:23 +05302359
Olli Etuahof119a262016-08-19 15:54:22 +03002360 case EOpExp:
2361 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2362 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302363
Olli Etuahof119a262016-08-19 15:54:22 +03002364 case EOpLog:
2365 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2366 if (operandArray[i].getFConst() <= 0.0f)
2367 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2368 diagnostics, &resultArray[i]);
2369 else
2370 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2371 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302372
Olli Etuahof119a262016-08-19 15:54:22 +03002373 case EOpExp2:
2374 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2375 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302376
Olli Etuahof119a262016-08-19 15:54:22 +03002377 case EOpLog2:
2378 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2379 // And log2f is not available on some plarforms like old android, so just using
2380 // log(x)/log(2) here.
2381 if (operandArray[i].getFConst() <= 0.0f)
2382 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2383 diagnostics, &resultArray[i]);
2384 else
2385 {
2386 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2387 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2388 }
2389 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302390
Olli Etuahof119a262016-08-19 15:54:22 +03002391 case EOpSqrt:
2392 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2393 if (operandArray[i].getFConst() < 0.0f)
2394 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2395 diagnostics, &resultArray[i]);
2396 else
2397 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2398 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302399
Olli Etuahof119a262016-08-19 15:54:22 +03002400 case EOpInverseSqrt:
2401 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2402 // so getting the square root first using builtin function sqrt() and then taking
2403 // its inverse.
2404 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2405 // result to 0.
2406 if (operandArray[i].getFConst() <= 0.0f)
2407 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2408 diagnostics, &resultArray[i]);
2409 else
2410 {
2411 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2412 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2413 }
2414 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302415
Olli Etuahod68924e2017-01-02 17:34:40 +00002416 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002417 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302418 resultArray[i].setBConst(!operandArray[i].getBConst());
2419 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302420
Olli Etuahof119a262016-08-19 15:54:22 +03002421 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302422 {
Olli Etuahof119a262016-08-19 15:54:22 +03002423 ASSERT(getType().getBasicType() == EbtFloat);
2424 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302425 float length = VectorLength(operandArray, objectSize);
2426 if (length)
2427 resultArray[i].setFConst(x / length);
2428 else
Olli Etuahof119a262016-08-19 15:54:22 +03002429 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2430 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302431 break;
2432 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002433 case EOpBitfieldReverse:
2434 {
2435 uint32_t value;
2436 if (getType().getBasicType() == EbtInt)
2437 {
2438 value = static_cast<uint32_t>(operandArray[i].getIConst());
2439 }
2440 else
2441 {
2442 ASSERT(getType().getBasicType() == EbtUInt);
2443 value = operandArray[i].getUConst();
2444 }
2445 uint32_t result = gl::BitfieldReverse(value);
2446 if (getType().getBasicType() == EbtInt)
2447 {
2448 resultArray[i].setIConst(static_cast<int32_t>(result));
2449 }
2450 else
2451 {
2452 resultArray[i].setUConst(result);
2453 }
2454 break;
2455 }
2456 case EOpBitCount:
2457 {
2458 uint32_t value;
2459 if (getType().getBasicType() == EbtInt)
2460 {
2461 value = static_cast<uint32_t>(operandArray[i].getIConst());
2462 }
2463 else
2464 {
2465 ASSERT(getType().getBasicType() == EbtUInt);
2466 value = operandArray[i].getUConst();
2467 }
2468 int result = gl::BitCount(value);
2469 resultArray[i].setIConst(result);
2470 break;
2471 }
2472 case EOpFindLSB:
2473 {
2474 uint32_t value;
2475 if (getType().getBasicType() == EbtInt)
2476 {
2477 value = static_cast<uint32_t>(operandArray[i].getIConst());
2478 }
2479 else
2480 {
2481 ASSERT(getType().getBasicType() == EbtUInt);
2482 value = operandArray[i].getUConst();
2483 }
2484 resultArray[i].setIConst(gl::FindLSB(value));
2485 break;
2486 }
2487 case EOpFindMSB:
2488 {
2489 uint32_t value;
2490 if (getType().getBasicType() == EbtInt)
2491 {
2492 int intValue = operandArray[i].getIConst();
2493 value = static_cast<uint32_t>(intValue);
2494 if (intValue < 0)
2495 {
2496 // Look for zero instead of one in value. This also handles the intValue ==
2497 // -1 special case, where the return value needs to be -1.
2498 value = ~value;
2499 }
2500 }
2501 else
2502 {
2503 ASSERT(getType().getBasicType() == EbtUInt);
2504 value = operandArray[i].getUConst();
2505 }
2506 resultArray[i].setIConst(gl::FindMSB(value));
2507 break;
2508 }
Olli Etuahof119a262016-08-19 15:54:22 +03002509 case EOpDFdx:
2510 case EOpDFdy:
2511 case EOpFwidth:
2512 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302513 // Derivatives of constant arguments should be 0.
2514 resultArray[i].setFConst(0.0f);
2515 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302516
Olli Etuahof119a262016-08-19 15:54:22 +03002517 default:
2518 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302519 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302520 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002521
Arun Patoleab2b9a22015-07-06 18:27:56 +05302522 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002523}
2524
Olli Etuahof119a262016-08-19 15:54:22 +03002525void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2526 FloatTypeUnaryFunc builtinFunc,
2527 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302528{
2529 ASSERT(builtinFunc);
2530
Olli Etuahof119a262016-08-19 15:54:22 +03002531 ASSERT(getType().getBasicType() == EbtFloat);
2532 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302533}
2534
Jamie Madillb1a85f42014-08-19 15:23:24 -04002535// static
Olli Etuahof119a262016-08-19 15:54:22 +03002536TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002537{
2538 ASSERT(aggregate->getSequence()->size() > 0u);
2539 size_t resultSize = aggregate->getType().getObjectSize();
2540 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2541 TBasicType basicType = aggregate->getBasicType();
2542
2543 size_t resultIndex = 0u;
2544
2545 if (aggregate->getSequence()->size() == 1u)
2546 {
2547 TIntermNode *argument = aggregate->getSequence()->front();
2548 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2549 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2550 // Check the special case of constructing a matrix diagonal from a single scalar,
2551 // or a vector from a single scalar.
2552 if (argumentConstant->getType().getObjectSize() == 1u)
2553 {
2554 if (aggregate->isMatrix())
2555 {
2556 int resultCols = aggregate->getType().getCols();
2557 int resultRows = aggregate->getType().getRows();
2558 for (int col = 0; col < resultCols; ++col)
2559 {
2560 for (int row = 0; row < resultRows; ++row)
2561 {
2562 if (col == row)
2563 {
2564 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2565 }
2566 else
2567 {
2568 resultArray[resultIndex].setFConst(0.0f);
2569 }
2570 ++resultIndex;
2571 }
2572 }
2573 }
2574 else
2575 {
2576 while (resultIndex < resultSize)
2577 {
2578 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2579 ++resultIndex;
2580 }
2581 }
2582 ASSERT(resultIndex == resultSize);
2583 return resultArray;
2584 }
2585 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2586 {
2587 // The special case of constructing a matrix from a matrix.
2588 int argumentCols = argumentConstant->getType().getCols();
2589 int argumentRows = argumentConstant->getType().getRows();
2590 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002591 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002592 for (int col = 0; col < resultCols; ++col)
2593 {
2594 for (int row = 0; row < resultRows; ++row)
2595 {
2596 if (col < argumentCols && row < argumentRows)
2597 {
2598 resultArray[resultIndex].cast(basicType,
2599 argumentUnionArray[col * argumentRows + row]);
2600 }
2601 else if (col == row)
2602 {
2603 resultArray[resultIndex].setFConst(1.0f);
2604 }
2605 else
2606 {
2607 resultArray[resultIndex].setFConst(0.0f);
2608 }
2609 ++resultIndex;
2610 }
2611 }
2612 ASSERT(resultIndex == resultSize);
2613 return resultArray;
2614 }
2615 }
2616
2617 for (TIntermNode *&argument : *aggregate->getSequence())
2618 {
2619 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2620 size_t argumentSize = argumentConstant->getType().getObjectSize();
2621 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2622 for (size_t i = 0u; i < argumentSize; ++i)
2623 {
2624 if (resultIndex >= resultSize)
2625 break;
2626 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2627 ++resultIndex;
2628 }
2629 }
2630 ASSERT(resultIndex == resultSize);
2631 return resultArray;
2632}
2633
2634// static
Olli Etuahof119a262016-08-19 15:54:22 +03002635TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2636 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302637{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002638 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002639 TIntermSequence *arguments = aggregate->getSequence();
2640 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2641 std::vector<const TConstantUnion *> unionArrays(argsCount);
2642 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002643 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302644 TBasicType basicType = EbtVoid;
2645 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002646 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302647 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002648 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2649 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302650
2651 if (i == 0)
2652 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002653 basicType = argConstant->getType().getBasicType();
2654 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302655 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002656 unionArrays[i] = argConstant->getUnionArrayPointer();
2657 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002658 if (objectSizes[i] > maxObjectSize)
2659 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302660 }
2661
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002662 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302663 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002664 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302665 if (objectSizes[i] != maxObjectSize)
2666 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2667 }
Arun Patole274f0702015-05-05 13:33:30 +05302668
Olli Etuahob43846e2015-06-02 18:18:57 +03002669 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002670
2671 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302672 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002673 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302674 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002675 ASSERT(basicType == EbtFloat);
2676 resultArray = new TConstantUnion[maxObjectSize];
2677 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302678 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002679 float y = unionArrays[0][i].getFConst();
2680 float x = unionArrays[1][i].getFConst();
2681 // Results are undefined if x and y are both 0.
2682 if (x == 0.0f && y == 0.0f)
2683 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2684 else
2685 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302686 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002687 break;
2688 }
Arun Patolebf790422015-05-18 17:53:04 +05302689
Olli Etuaho51182ab2017-01-22 00:12:29 +00002690 case EOpPow:
2691 {
2692 ASSERT(basicType == EbtFloat);
2693 resultArray = new TConstantUnion[maxObjectSize];
2694 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302695 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002696 float x = unionArrays[0][i].getFConst();
2697 float y = unionArrays[1][i].getFConst();
2698 // Results are undefined if x < 0.
2699 // Results are undefined if x = 0 and y <= 0.
2700 if (x < 0.0f)
2701 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2702 else if (x == 0.0f && y <= 0.0f)
2703 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2704 else
2705 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302706 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002707 break;
2708 }
Arun Patolebf790422015-05-18 17:53:04 +05302709
Olli Etuaho51182ab2017-01-22 00:12:29 +00002710 case EOpMod:
2711 {
2712 ASSERT(basicType == EbtFloat);
2713 resultArray = new TConstantUnion[maxObjectSize];
2714 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302715 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002716 float x = unionArrays[0][i].getFConst();
2717 float y = unionArrays[1][i].getFConst();
2718 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302719 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002720 break;
2721 }
Arun Patolebf790422015-05-18 17:53:04 +05302722
Olli Etuaho51182ab2017-01-22 00:12:29 +00002723 case EOpMin:
2724 {
2725 resultArray = new TConstantUnion[maxObjectSize];
2726 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302727 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002728 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302729 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002730 case EbtFloat:
2731 resultArray[i].setFConst(
2732 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2733 break;
2734 case EbtInt:
2735 resultArray[i].setIConst(
2736 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2737 break;
2738 case EbtUInt:
2739 resultArray[i].setUConst(
2740 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2741 break;
2742 default:
2743 UNREACHABLE();
2744 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302745 }
2746 }
2747 break;
Arun Patole274f0702015-05-05 13:33:30 +05302748 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002749
2750 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302751 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002752 resultArray = new TConstantUnion[maxObjectSize];
2753 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302754 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002755 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302756 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002757 case EbtFloat:
2758 resultArray[i].setFConst(
2759 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2760 break;
2761 case EbtInt:
2762 resultArray[i].setIConst(
2763 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2764 break;
2765 case EbtUInt:
2766 resultArray[i].setUConst(
2767 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2768 break;
2769 default:
2770 UNREACHABLE();
2771 break;
Arun Patole274f0702015-05-05 13:33:30 +05302772 }
2773 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002774 break;
Arun Patole274f0702015-05-05 13:33:30 +05302775 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002776
2777 case EOpStep:
2778 {
2779 ASSERT(basicType == EbtFloat);
2780 resultArray = new TConstantUnion[maxObjectSize];
2781 for (size_t i = 0; i < maxObjectSize; i++)
2782 resultArray[i].setFConst(
2783 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2784 break;
2785 }
2786
2787 case EOpLessThanComponentWise:
2788 {
2789 resultArray = new TConstantUnion[maxObjectSize];
2790 for (size_t i = 0; i < maxObjectSize; i++)
2791 {
2792 switch (basicType)
2793 {
2794 case EbtFloat:
2795 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2796 unionArrays[1][i].getFConst());
2797 break;
2798 case EbtInt:
2799 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2800 unionArrays[1][i].getIConst());
2801 break;
2802 case EbtUInt:
2803 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2804 unionArrays[1][i].getUConst());
2805 break;
2806 default:
2807 UNREACHABLE();
2808 break;
2809 }
2810 }
2811 break;
2812 }
2813
2814 case EOpLessThanEqualComponentWise:
2815 {
2816 resultArray = new TConstantUnion[maxObjectSize];
2817 for (size_t i = 0; i < maxObjectSize; i++)
2818 {
2819 switch (basicType)
2820 {
2821 case EbtFloat:
2822 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2823 unionArrays[1][i].getFConst());
2824 break;
2825 case EbtInt:
2826 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2827 unionArrays[1][i].getIConst());
2828 break;
2829 case EbtUInt:
2830 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2831 unionArrays[1][i].getUConst());
2832 break;
2833 default:
2834 UNREACHABLE();
2835 break;
2836 }
2837 }
2838 break;
2839 }
2840
2841 case EOpGreaterThanComponentWise:
2842 {
2843 resultArray = new TConstantUnion[maxObjectSize];
2844 for (size_t i = 0; i < maxObjectSize; i++)
2845 {
2846 switch (basicType)
2847 {
2848 case EbtFloat:
2849 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2850 unionArrays[1][i].getFConst());
2851 break;
2852 case EbtInt:
2853 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2854 unionArrays[1][i].getIConst());
2855 break;
2856 case EbtUInt:
2857 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2858 unionArrays[1][i].getUConst());
2859 break;
2860 default:
2861 UNREACHABLE();
2862 break;
2863 }
2864 }
2865 break;
2866 }
2867 case EOpGreaterThanEqualComponentWise:
2868 {
2869 resultArray = new TConstantUnion[maxObjectSize];
2870 for (size_t i = 0; i < maxObjectSize; i++)
2871 {
2872 switch (basicType)
2873 {
2874 case EbtFloat:
2875 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2876 unionArrays[1][i].getFConst());
2877 break;
2878 case EbtInt:
2879 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2880 unionArrays[1][i].getIConst());
2881 break;
2882 case EbtUInt:
2883 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2884 unionArrays[1][i].getUConst());
2885 break;
2886 default:
2887 UNREACHABLE();
2888 break;
2889 }
2890 }
2891 }
2892 break;
2893
2894 case EOpEqualComponentWise:
2895 {
2896 resultArray = new TConstantUnion[maxObjectSize];
2897 for (size_t i = 0; i < maxObjectSize; i++)
2898 {
2899 switch (basicType)
2900 {
2901 case EbtFloat:
2902 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2903 unionArrays[1][i].getFConst());
2904 break;
2905 case EbtInt:
2906 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2907 unionArrays[1][i].getIConst());
2908 break;
2909 case EbtUInt:
2910 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2911 unionArrays[1][i].getUConst());
2912 break;
2913 case EbtBool:
2914 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2915 unionArrays[1][i].getBConst());
2916 break;
2917 default:
2918 UNREACHABLE();
2919 break;
2920 }
2921 }
2922 break;
2923 }
2924
2925 case EOpNotEqualComponentWise:
2926 {
2927 resultArray = new TConstantUnion[maxObjectSize];
2928 for (size_t i = 0; i < maxObjectSize; i++)
2929 {
2930 switch (basicType)
2931 {
2932 case EbtFloat:
2933 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2934 unionArrays[1][i].getFConst());
2935 break;
2936 case EbtInt:
2937 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2938 unionArrays[1][i].getIConst());
2939 break;
2940 case EbtUInt:
2941 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2942 unionArrays[1][i].getUConst());
2943 break;
2944 case EbtBool:
2945 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2946 unionArrays[1][i].getBConst());
2947 break;
2948 default:
2949 UNREACHABLE();
2950 break;
2951 }
2952 }
2953 break;
2954 }
2955
2956 case EOpDistance:
2957 {
2958 ASSERT(basicType == EbtFloat);
2959 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2960 resultArray = new TConstantUnion();
2961 for (size_t i = 0; i < maxObjectSize; i++)
2962 {
2963 float x = unionArrays[0][i].getFConst();
2964 float y = unionArrays[1][i].getFConst();
2965 distanceArray[i].setFConst(x - y);
2966 }
2967 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2968 break;
2969 }
2970
2971 case EOpDot:
2972 ASSERT(basicType == EbtFloat);
2973 resultArray = new TConstantUnion();
2974 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2975 break;
2976
2977 case EOpCross:
2978 {
2979 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2980 resultArray = new TConstantUnion[maxObjectSize];
2981 float x0 = unionArrays[0][0].getFConst();
2982 float x1 = unionArrays[0][1].getFConst();
2983 float x2 = unionArrays[0][2].getFConst();
2984 float y0 = unionArrays[1][0].getFConst();
2985 float y1 = unionArrays[1][1].getFConst();
2986 float y2 = unionArrays[1][2].getFConst();
2987 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2988 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2989 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2990 break;
2991 }
2992
2993 case EOpReflect:
2994 {
2995 ASSERT(basicType == EbtFloat);
2996 // genType reflect (genType I, genType N) :
2997 // For the incident vector I and surface orientation N, returns the reflection
2998 // direction:
2999 // I - 2 * dot(N, I) * N.
3000 resultArray = new TConstantUnion[maxObjectSize];
3001 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3002 for (size_t i = 0; i < maxObjectSize; i++)
3003 {
3004 float result = unionArrays[0][i].getFConst() -
3005 2.0f * dotProduct * unionArrays[1][i].getFConst();
3006 resultArray[i].setFConst(result);
3007 }
3008 break;
3009 }
3010
3011 case EOpMulMatrixComponentWise:
3012 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003013 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3014 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003015 // Perform component-wise matrix multiplication.
3016 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003017 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003018 angle::Matrix<float> result =
3019 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3020 SetUnionArrayFromMatrix(result, resultArray);
3021 break;
3022 }
3023
3024 case EOpOuterProduct:
3025 {
3026 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003027 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3028 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003029 resultArray = new TConstantUnion[numRows * numCols];
3030 angle::Matrix<float> result =
3031 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3032 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3033 SetUnionArrayFromMatrix(result, resultArray);
3034 break;
3035 }
3036
3037 case EOpClamp:
3038 {
3039 resultArray = new TConstantUnion[maxObjectSize];
3040 for (size_t i = 0; i < maxObjectSize; i++)
3041 {
3042 switch (basicType)
3043 {
3044 case EbtFloat:
3045 {
3046 float x = unionArrays[0][i].getFConst();
3047 float min = unionArrays[1][i].getFConst();
3048 float max = unionArrays[2][i].getFConst();
3049 // Results are undefined if min > max.
3050 if (min > max)
3051 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3052 &resultArray[i]);
3053 else
3054 resultArray[i].setFConst(gl::clamp(x, min, max));
3055 break;
3056 }
3057
3058 case EbtInt:
3059 {
3060 int x = unionArrays[0][i].getIConst();
3061 int min = unionArrays[1][i].getIConst();
3062 int max = unionArrays[2][i].getIConst();
3063 // Results are undefined if min > max.
3064 if (min > max)
3065 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3066 &resultArray[i]);
3067 else
3068 resultArray[i].setIConst(gl::clamp(x, min, max));
3069 break;
3070 }
3071 case EbtUInt:
3072 {
3073 unsigned int x = unionArrays[0][i].getUConst();
3074 unsigned int min = unionArrays[1][i].getUConst();
3075 unsigned int max = unionArrays[2][i].getUConst();
3076 // Results are undefined if min > max.
3077 if (min > max)
3078 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3079 &resultArray[i]);
3080 else
3081 resultArray[i].setUConst(gl::clamp(x, min, max));
3082 break;
3083 }
3084 default:
3085 UNREACHABLE();
3086 break;
3087 }
3088 }
3089 break;
3090 }
3091
3092 case EOpMix:
3093 {
3094 ASSERT(basicType == EbtFloat);
3095 resultArray = new TConstantUnion[maxObjectSize];
3096 for (size_t i = 0; i < maxObjectSize; i++)
3097 {
3098 float x = unionArrays[0][i].getFConst();
3099 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003100 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003101 if (type == EbtFloat)
3102 {
3103 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3104 float a = unionArrays[2][i].getFConst();
3105 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3106 }
3107 else // 3rd parameter is EbtBool
3108 {
3109 ASSERT(type == EbtBool);
3110 // Selects which vector each returned component comes from.
3111 // For a component of a that is false, the corresponding component of x is
3112 // returned.
3113 // For a component of a that is true, the corresponding component of y is
3114 // returned.
3115 bool a = unionArrays[2][i].getBConst();
3116 resultArray[i].setFConst(a ? y : x);
3117 }
3118 }
3119 break;
3120 }
3121
3122 case EOpSmoothStep:
3123 {
3124 ASSERT(basicType == EbtFloat);
3125 resultArray = new TConstantUnion[maxObjectSize];
3126 for (size_t i = 0; i < maxObjectSize; i++)
3127 {
3128 float edge0 = unionArrays[0][i].getFConst();
3129 float edge1 = unionArrays[1][i].getFConst();
3130 float x = unionArrays[2][i].getFConst();
3131 // Results are undefined if edge0 >= edge1.
3132 if (edge0 >= edge1)
3133 {
3134 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3135 }
3136 else
3137 {
3138 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3139 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3140 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3141 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3142 }
3143 }
3144 break;
3145 }
3146
Olli Etuaho74da73f2017-02-01 15:37:48 +00003147 case EOpLdexp:
3148 {
3149 resultArray = new TConstantUnion[maxObjectSize];
3150 for (size_t i = 0; i < maxObjectSize; i++)
3151 {
3152 float x = unionArrays[0][i].getFConst();
3153 int exp = unionArrays[1][i].getIConst();
3154 if (exp > 128)
3155 {
3156 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3157 }
3158 else
3159 {
3160 resultArray[i].setFConst(gl::Ldexp(x, exp));
3161 }
3162 }
3163 break;
3164 }
3165
Jamie Madille72595b2017-06-06 15:12:26 -04003166 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003167 {
3168 ASSERT(basicType == EbtFloat);
3169 // genType faceforward(genType N, genType I, genType Nref) :
3170 // If dot(Nref, I) < 0 return N, otherwise return -N.
3171 resultArray = new TConstantUnion[maxObjectSize];
3172 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3173 for (size_t i = 0; i < maxObjectSize; i++)
3174 {
3175 if (dotProduct < 0)
3176 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3177 else
3178 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3179 }
3180 break;
3181 }
3182
3183 case EOpRefract:
3184 {
3185 ASSERT(basicType == EbtFloat);
3186 // genType refract(genType I, genType N, float eta) :
3187 // For the incident vector I and surface normal N, and the ratio of indices of
3188 // refraction eta,
3189 // return the refraction vector. The result is computed by
3190 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3191 // if (k < 0.0)
3192 // return genType(0.0)
3193 // else
3194 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3195 resultArray = new TConstantUnion[maxObjectSize];
3196 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3197 for (size_t i = 0; i < maxObjectSize; i++)
3198 {
3199 float eta = unionArrays[2][i].getFConst();
3200 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3201 if (k < 0.0f)
3202 resultArray[i].setFConst(0.0f);
3203 else
3204 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3205 (eta * dotProduct + sqrtf(k)) *
3206 unionArrays[1][i].getFConst());
3207 }
3208 break;
3209 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003210 case EOpBitfieldExtract:
3211 {
3212 resultArray = new TConstantUnion[maxObjectSize];
3213 for (size_t i = 0; i < maxObjectSize; ++i)
3214 {
3215 int offset = unionArrays[1][0].getIConst();
3216 int bits = unionArrays[2][0].getIConst();
3217 if (bits == 0)
3218 {
3219 if (aggregate->getBasicType() == EbtInt)
3220 {
3221 resultArray[i].setIConst(0);
3222 }
3223 else
3224 {
3225 ASSERT(aggregate->getBasicType() == EbtUInt);
3226 resultArray[i].setUConst(0);
3227 }
3228 }
3229 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3230 {
3231 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3232 &resultArray[i]);
3233 }
3234 else
3235 {
3236 // bits can be 32 here, so we need to avoid bit shift overflow.
3237 uint32_t maskMsb = 1u << (bits - 1);
3238 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3239 if (aggregate->getBasicType() == EbtInt)
3240 {
3241 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3242 uint32_t resultUnsigned = (value & mask) >> offset;
3243 if ((resultUnsigned & maskMsb) != 0)
3244 {
3245 // The most significant bits (from bits+1 to the most significant bit)
3246 // should be set to 1.
3247 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3248 resultUnsigned |= higherBitsMask;
3249 }
3250 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3251 }
3252 else
3253 {
3254 ASSERT(aggregate->getBasicType() == EbtUInt);
3255 uint32_t value = unionArrays[0][i].getUConst();
3256 resultArray[i].setUConst((value & mask) >> offset);
3257 }
3258 }
3259 }
3260 break;
3261 }
3262 case EOpBitfieldInsert:
3263 {
3264 resultArray = new TConstantUnion[maxObjectSize];
3265 for (size_t i = 0; i < maxObjectSize; ++i)
3266 {
3267 int offset = unionArrays[2][0].getIConst();
3268 int bits = unionArrays[3][0].getIConst();
3269 if (bits == 0)
3270 {
3271 if (aggregate->getBasicType() == EbtInt)
3272 {
3273 int32_t base = unionArrays[0][i].getIConst();
3274 resultArray[i].setIConst(base);
3275 }
3276 else
3277 {
3278 ASSERT(aggregate->getBasicType() == EbtUInt);
3279 uint32_t base = unionArrays[0][i].getUConst();
3280 resultArray[i].setUConst(base);
3281 }
3282 }
3283 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3284 {
3285 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3286 &resultArray[i]);
3287 }
3288 else
3289 {
3290 // bits can be 32 here, so we need to avoid bit shift overflow.
3291 uint32_t maskMsb = 1u << (bits - 1);
3292 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3293 uint32_t baseMask = ~insertMask;
3294 if (aggregate->getBasicType() == EbtInt)
3295 {
3296 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3297 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3298 uint32_t resultUnsigned =
3299 (base & baseMask) | ((insert << offset) & insertMask);
3300 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3301 }
3302 else
3303 {
3304 ASSERT(aggregate->getBasicType() == EbtUInt);
3305 uint32_t base = unionArrays[0][i].getUConst();
3306 uint32_t insert = unionArrays[1][i].getUConst();
3307 resultArray[i].setUConst((base & baseMask) |
3308 ((insert << offset) & insertMask));
3309 }
3310 }
3311 }
3312 break;
3313 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003314
3315 default:
3316 UNREACHABLE();
3317 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303318 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003319 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303320}
3321
Jamie Madill45bcc782016-11-07 13:58:48 -05003322} // namespace sh