blob: 3d1b483c9097eca87313ac1339ef5238686bf0a2 [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"
Olli Etuahofbb1c792018-01-19 16:26:59 +020021#include "compiler/translator/ImmutableString.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040022#include "compiler/translator/IntermNode.h"
23#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040024#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040025
Jamie Madill45bcc782016-11-07 13:58:48 -050026namespace sh
27{
28
Jamie Madillb1a85f42014-08-19 15:23:24 -040029namespace
30{
31
Jamie Madilld7b1ab52016-12-12 14:42:19 -050032const float kPi = 3.14159265358979323846f;
Arun Patole9dea48f2015-04-02 11:45:09 +053033const float kDegreesToRadiansMultiplier = kPi / 180.0f;
34const float kRadiansToDegreesMultiplier = 180.0f / kPi;
35
Jamie Madillb1a85f42014-08-19 15:23:24 -040036TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
37{
38 return left > right ? left : right;
39}
40
Arun Patole274f0702015-05-05 13:33:30 +053041TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
42{
43 TConstantUnion *constUnion = new TConstantUnion[size];
44 for (unsigned int i = 0; i < size; ++i)
Jamie Madilld7b1ab52016-12-12 14:42:19 -050045 constUnion[i] = constant;
Arun Patole274f0702015-05-05 13:33:30 +053046
47 return constUnion;
48}
49
Olli Etuahof119a262016-08-19 15:54:22 +030050void UndefinedConstantFoldingError(const TSourceLoc &loc,
51 TOperator op,
52 TBasicType basicType,
53 TDiagnostics *diagnostics,
54 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053055{
Olli Etuahof119a262016-08-19 15:54:22 +030056 diagnostics->warning(loc, "operation result is undefined for the values passed in",
Olli Etuaho4de340a2016-12-16 09:32:03 +000057 GetOperatorString(op));
Arun Patolebf790422015-05-18 17:53:04 +053058
59 switch (basicType)
60 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050061 case EbtFloat:
62 result->setFConst(0.0f);
63 break;
64 case EbtInt:
65 result->setIConst(0);
66 break;
67 case EbtUInt:
68 result->setUConst(0u);
69 break;
70 case EbtBool:
71 result->setBConst(false);
72 break;
73 default:
74 break;
Arun Patolebf790422015-05-18 17:53:04 +053075 }
76}
77
Olli Etuaho5c0e0232015-11-11 15:55:59 +020078float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053079{
80 float result = 0.0f;
81 for (size_t i = 0; i < paramArraySize; i++)
82 {
83 float f = paramArray[i].getFConst();
84 result += f * f;
85 }
86 return sqrtf(result);
87}
88
Olli Etuaho5c0e0232015-11-11 15:55:59 +020089float VectorDotProduct(const TConstantUnion *paramArray1,
90 const TConstantUnion *paramArray2,
91 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053092{
93 float result = 0.0f;
94 for (size_t i = 0; i < paramArraySize; i++)
95 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
96 return result;
97}
98
Olli Etuaho2768bc82017-12-12 11:51:48 +020099TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray, const TIntermTyped *originalNode)
Olli Etuahob43846e2015-06-02 18:18:57 +0300100{
Olli Etuaho2768bc82017-12-12 11:51:48 +0200101 ASSERT(constArray != nullptr);
102 // Note that we inherit whatever qualifier the folded node had. Nodes may be constant folded
103 // without being qualified as constant.
Olli Etuahob43846e2015-06-02 18:18:57 +0300104 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuahob43846e2015-06-02 18:18:57 +0300105 folded->setLine(originalNode->getLine());
106 return folded;
107}
108
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200109angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
110 const unsigned int &rows,
111 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530112{
113 std::vector<float> elements;
114 for (size_t i = 0; i < rows * cols; i++)
115 elements.push_back(paramArray[i].getFConst());
116 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300117 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
118 // so that the created matrix will have the expected dimensions after the transpose.
119 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530120}
121
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200122angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530123{
124 std::vector<float> elements;
125 for (size_t i = 0; i < size * size; i++)
126 elements.push_back(paramArray[i].getFConst());
127 // Transpose is used since the Matrix constructor expects arguments in row-major order,
128 // whereas the paramArray is in column-major order.
129 return angle::Matrix<float>(elements, size).transpose();
130}
131
132void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
133{
134 // Transpose is used since the input Matrix is in row-major order,
135 // whereas the actual result should be in column-major order.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500136 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530137 std::vector<float> resultElements = result.elements();
138 for (size_t i = 0; i < resultElements.size(); i++)
139 resultArray[i].setFConst(resultElements[i]);
140}
141
Olli Etuaho765924f2018-01-04 12:48:36 +0200142bool CanFoldAggregateBuiltInOp(TOperator op)
143{
144 switch (op)
145 {
146 case EOpAtan:
147 case EOpPow:
148 case EOpMod:
149 case EOpMin:
150 case EOpMax:
151 case EOpClamp:
152 case EOpMix:
153 case EOpStep:
Olli Etuahof7f0b8c2018-02-21 20:02:23 +0200154 case EOpSmoothstep:
Olli Etuaho765924f2018-01-04 12:48:36 +0200155 case EOpLdexp:
156 case EOpMulMatrixComponentWise:
157 case EOpOuterProduct:
158 case EOpEqualComponentWise:
159 case EOpNotEqualComponentWise:
160 case EOpLessThanComponentWise:
161 case EOpLessThanEqualComponentWise:
162 case EOpGreaterThanComponentWise:
163 case EOpGreaterThanEqualComponentWise:
164 case EOpDistance:
165 case EOpDot:
166 case EOpCross:
167 case EOpFaceforward:
168 case EOpReflect:
169 case EOpRefract:
170 case EOpBitfieldExtract:
171 case EOpBitfieldInsert:
172 return true;
173 default:
174 return false;
175 }
176}
177
Jamie Madillb1a85f42014-08-19 15:23:24 -0400178} // namespace anonymous
179
Jamie Madillb1a85f42014-08-19 15:23:24 -0400180////////////////////////////////////////////////////////////////
181//
182// Member functions of the nodes used for building the tree.
183//
184////////////////////////////////////////////////////////////////
185
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200186TIntermExpression::TIntermExpression(const TType &t) : TIntermTyped(), mType(t)
187{
188}
189
190void TIntermExpression::setTypePreservePrecision(const TType &t)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300191{
192 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500193 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300194 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
195 mType.setPrecision(precision);
196}
197
Jamie Madillb1a85f42014-08-19 15:23:24 -0400198#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500199 if (node == original) \
200 { \
201 node = static_cast<type *>(replacement); \
202 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400203 }
204
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500205bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400206{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300207 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400208 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
209 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
210 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100211 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400212 return false;
213}
214
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500215bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400216{
217 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
218 return false;
219}
220
Olli Etuahob6fa0432016-09-28 16:28:05 +0100221bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
222{
223 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
224 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
225 return false;
226}
227
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500228bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400229{
230 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
231 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
232 return false;
233}
234
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500235bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400236{
Olli Etuahoa2234302016-08-31 12:05:39 +0300237 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400238 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
239 return false;
240}
241
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000242bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
243{
244 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
245 return false;
246}
247
Olli Etuaho336b1472016-10-05 16:37:55 +0100248bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
249{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000250 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100251 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
252 return false;
253}
254
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500255bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400256{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100257 return replaceChildNodeInternal(original, replacement);
258}
259
260bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
261{
262 return replaceChildNodeInternal(original, replacement);
263}
264
Olli Etuaho16c745a2017-01-16 17:02:27 +0000265bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
266{
Olli Etuahod4bd9632018-03-08 16:32:44 +0200267 return false;
Olli Etuaho16c745a2017-01-16 17:02:27 +0000268}
269
Olli Etuaho13389b62016-10-16 11:48:18 +0100270bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
271{
272 return replaceChildNodeInternal(original, replacement);
273}
274
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100275bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
276{
277 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400278 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100279 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400280 }
281 return false;
282}
283
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100284bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
285 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300286{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100287 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300288 {
289 if (*it == original)
290 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100291 it = getSequence()->erase(it);
292 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300293 return true;
294 }
295 }
296 return false;
297}
298
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100299bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
300 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300301{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100302 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300303 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300304 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300305 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100306 auto it = getSequence()->begin() + position;
307 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300308 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300309}
310
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200311TIntermSymbol::TIntermSymbol(const TVariable *variable) : TIntermTyped(), mVariable(variable)
Olli Etuaho195be942017-12-04 23:40:14 +0200312{
Olli Etuaho195be942017-12-04 23:40:14 +0200313}
314
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200315bool TIntermSymbol::hasConstantValue() const
316{
317 return variable().getConstPointer() != nullptr;
318}
319
320const TConstantUnion *TIntermSymbol::getConstantValue() const
321{
322 return variable().getConstPointer();
323}
324
Olli Etuahob6af22b2017-12-15 14:05:44 +0200325const TSymbolUniqueId &TIntermSymbol::uniqueId() const
326{
327 return mVariable->uniqueId();
328}
329
Olli Etuahofbb1c792018-01-19 16:26:59 +0200330ImmutableString TIntermSymbol::getName() const
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200331{
332 return mVariable->name();
333}
334
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200335const TType &TIntermSymbol::getType() const
336{
337 return mVariable->getType();
338}
339
Olli Etuahofe486322017-03-21 09:30:54 +0000340TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
341 TIntermSequence *arguments)
342{
Olli Etuaho0c371002017-12-13 17:00:25 +0400343 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000344}
345
Olli Etuaho0c371002017-12-13 17:00:25 +0400346TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
347 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000348{
Olli Etuaho0c371002017-12-13 17:00:25 +0400349 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000350}
351
352TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
353 TIntermSequence *arguments)
354{
Olli Etuahoe80825e2018-02-16 10:24:53 +0200355 // op should be either EOpCallBuiltInFunction or a specific math op.
356 ASSERT(func.getBuiltInOp() != EOpNull);
357 return new TIntermAggregate(&func, func.getReturnType(), func.getBuiltInOp(), arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000358}
359
360TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000361 TIntermSequence *arguments)
362{
Olli Etuaho0c371002017-12-13 17:00:25 +0400363 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000364}
365
Olli Etuaho0c371002017-12-13 17:00:25 +0400366TIntermAggregate::TIntermAggregate(const TFunction *func,
367 const TType &type,
368 TOperator op,
369 TIntermSequence *arguments)
Olli Etuahoe80825e2018-02-16 10:24:53 +0200370 : TIntermOperator(op, type),
Olli Etuaho0c371002017-12-13 17:00:25 +0400371 mUseEmulatedFunction(false),
372 mGotPrecisionFromChildren(false),
373 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800374{
375 if (arguments != nullptr)
376 {
377 mArguments.swap(*arguments);
378 }
Olli Etuaho1bb85282017-12-14 13:39:53 +0200379 ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
Olli Etuahoe80825e2018-02-16 10:24:53 +0200380 setPrecisionAndQualifier();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800381}
382
Olli Etuahoe80825e2018-02-16 10:24:53 +0200383void TIntermAggregate::setPrecisionAndQualifier()
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800384{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800385 mType.setQualifier(EvqTemporary);
Olli Etuahoe80825e2018-02-16 10:24:53 +0200386 if (mOp == EOpCallBuiltInFunction)
387 {
388 setBuiltInFunctionPrecision();
389 }
390 else if (!isFunctionCall())
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800391 {
392 if (isConstructor())
393 {
394 // Structs should not be precision qualified, the individual members may be.
395 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300396 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800397 {
398 setPrecisionFromChildren();
399 }
400 }
401 else
402 {
403 setPrecisionForBuiltInOp();
404 }
405 if (areChildrenConstQualified())
406 {
407 mType.setQualifier(EvqConst);
408 }
409 }
410}
411
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200412bool TIntermAggregate::areChildrenConstQualified()
413{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800414 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200415 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800416 TIntermTyped *typedArg = arg->getAsTyped();
417 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200418 {
419 return false;
420 }
421 }
422 return true;
423}
424
Olli Etuahod2a67b92014-10-21 16:42:57 +0300425void TIntermAggregate::setPrecisionFromChildren()
426{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300427 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300428 if (getBasicType() == EbtBool)
429 {
430 mType.setPrecision(EbpUndefined);
431 return;
432 }
433
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500434 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800435 TIntermSequence::iterator childIter = mArguments.begin();
436 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300437 {
438 TIntermTyped *typed = (*childIter)->getAsTyped();
439 if (typed)
440 precision = GetHigherPrecision(typed->getPrecision(), precision);
441 ++childIter;
442 }
443 mType.setPrecision(precision);
444}
445
Olli Etuaho9250cb22017-01-21 10:51:27 +0000446void TIntermAggregate::setPrecisionForBuiltInOp()
447{
448 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800449 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000450 if (!setPrecisionForSpecialBuiltInOp())
451 {
452 setPrecisionFromChildren();
453 }
454}
455
456bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
457{
458 switch (mOp)
459 {
460 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800461 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
462 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000463 return true;
464 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800465 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
466 mArguments[1]->getAsTyped()->getPrecision()));
467 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000468 return true;
469 case EOpUaddCarry:
470 case EOpUsubBorrow:
471 mType.setPrecision(EbpHigh);
472 return true;
473 default:
474 return false;
475 }
476}
477
Olli Etuahod2a67b92014-10-21 16:42:57 +0300478void TIntermAggregate::setBuiltInFunctionPrecision()
479{
480 // All built-ins returning bool should be handled as ops, not functions.
481 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800482 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300483
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800484 TPrecision precision = EbpUndefined;
485 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300486 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800487 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300488 // ESSL spec section 8: texture functions get their precision from the sampler.
489 if (typed && IsSampler(typed->getBasicType()))
490 {
491 precision = typed->getPrecision();
492 break;
493 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300494 }
495 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
496 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahofbb1c792018-01-19 16:26:59 +0200497 if (mFunction->name() == "textureSize")
Olli Etuahod2a67b92014-10-21 16:42:57 +0300498 mType.setPrecision(EbpHigh);
499 else
500 mType.setPrecision(precision);
501}
502
Olli Etuaho0c371002017-12-13 17:00:25 +0400503const char *TIntermAggregate::functionName() const
504{
505 ASSERT(!isConstructor());
506 switch (mOp)
507 {
508 case EOpCallInternalRawFunction:
509 case EOpCallBuiltInFunction:
510 case EOpCallFunctionInAST:
Olli Etuahofbb1c792018-01-19 16:26:59 +0200511 return mFunction->name().data();
Olli Etuaho0c371002017-12-13 17:00:25 +0400512 default:
513 return GetOperatorString(mOp);
514 }
515}
516
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200517bool TIntermAggregate::hasConstantValue() const
518{
519 if (!isConstructor())
520 {
521 return false;
522 }
523 for (TIntermNode *constructorArg : mArguments)
524 {
525 if (!constructorArg->getAsTyped()->hasConstantValue())
526 {
527 return false;
528 }
529 }
530 return true;
531}
532
533const TConstantUnion *TIntermAggregate::getConstantValue() const
534{
535 if (!hasConstantValue())
536 {
537 return nullptr;
538 }
539 ASSERT(isConstructor());
540 ASSERT(mArguments.size() > 0u);
541
542 TConstantUnion *constArray = nullptr;
543 if (isArray())
544 {
545 size_t elementSize = mArguments.front()->getAsTyped()->getType().getObjectSize();
546 constArray = new TConstantUnion[elementSize * getOutermostArraySize()];
547
548 size_t elementOffset = 0u;
549 for (TIntermNode *constructorArg : mArguments)
550 {
551 const TConstantUnion *elementConstArray =
552 constructorArg->getAsTyped()->getConstantValue();
553 ASSERT(elementConstArray);
554 size_t elementSizeBytes = sizeof(TConstantUnion) * elementSize;
555 memcpy(static_cast<void *>(&constArray[elementOffset]),
556 static_cast<const void *>(elementConstArray), elementSizeBytes);
557 elementOffset += elementSize;
558 }
559 return constArray;
560 }
561
562 size_t resultSize = getType().getObjectSize();
563 constArray = new TConstantUnion[resultSize];
564 TBasicType basicType = getBasicType();
565
566 size_t resultIndex = 0u;
567
568 if (mArguments.size() == 1u)
569 {
570 TIntermNode *argument = mArguments.front();
571 TIntermTyped *argumentTyped = argument->getAsTyped();
572 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
573 // Check the special case of constructing a matrix diagonal from a single scalar,
574 // or a vector from a single scalar.
575 if (argumentTyped->getType().getObjectSize() == 1u)
576 {
577 if (isMatrix())
578 {
579 int resultCols = getType().getCols();
580 int resultRows = getType().getRows();
581 for (int col = 0; col < resultCols; ++col)
582 {
583 for (int row = 0; row < resultRows; ++row)
584 {
585 if (col == row)
586 {
587 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
588 }
589 else
590 {
591 constArray[resultIndex].setFConst(0.0f);
592 }
593 ++resultIndex;
594 }
595 }
596 }
597 else
598 {
599 while (resultIndex < resultSize)
600 {
601 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
602 ++resultIndex;
603 }
604 }
605 ASSERT(resultIndex == resultSize);
606 return constArray;
607 }
608 else if (isMatrix() && argumentTyped->isMatrix())
609 {
610 // The special case of constructing a matrix from a matrix.
611 int argumentCols = argumentTyped->getType().getCols();
612 int argumentRows = argumentTyped->getType().getRows();
613 int resultCols = getType().getCols();
614 int resultRows = getType().getRows();
615 for (int col = 0; col < resultCols; ++col)
616 {
617 for (int row = 0; row < resultRows; ++row)
618 {
619 if (col < argumentCols && row < argumentRows)
620 {
621 constArray[resultIndex].cast(
622 basicType, argumentConstantValue[col * argumentRows + row]);
623 }
624 else if (col == row)
625 {
626 constArray[resultIndex].setFConst(1.0f);
627 }
628 else
629 {
630 constArray[resultIndex].setFConst(0.0f);
631 }
632 ++resultIndex;
633 }
634 }
635 ASSERT(resultIndex == resultSize);
636 return constArray;
637 }
638 }
639
640 for (TIntermNode *argument : mArguments)
641 {
642 TIntermTyped *argumentTyped = argument->getAsTyped();
643 size_t argumentSize = argumentTyped->getType().getObjectSize();
644 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
645 for (size_t i = 0u; i < argumentSize; ++i)
646 {
647 if (resultIndex >= resultSize)
648 break;
649 constArray[resultIndex].cast(basicType, argumentConstantValue[i]);
650 ++resultIndex;
651 }
652 }
653 ASSERT(resultIndex == resultSize);
654 return constArray;
655}
656
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300657bool TIntermAggregate::hasSideEffects() const
658{
Olli Etuahoea78d2b2018-01-09 12:55:27 +0200659 if (getQualifier() == EvqConst)
660 {
661 return false;
662 }
663 bool calledFunctionHasNoSideEffects =
664 isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects();
665 if (calledFunctionHasNoSideEffects || isConstructor())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300666 {
667 for (TIntermNode *arg : mArguments)
668 {
669 if (arg->getAsTyped()->hasSideEffects())
670 {
671 return true;
672 }
673 }
674 return false;
675 }
676 // Conservatively assume most aggregate operators have side-effects
677 return true;
678}
679
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100680void TIntermBlock::appendStatement(TIntermNode *statement)
681{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300682 // Declaration nodes with no children can appear if it was an empty declaration or if all the
683 // declarators just added constants to the symbol table instead of generating code. We still
684 // need to add the declaration to the AST in that case because it might be relevant to the
685 // validity of switch/case.
686 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100687 {
688 mStatements.push_back(statement);
689 }
690}
691
Olli Etuaho13389b62016-10-16 11:48:18 +0100692void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
693{
694 ASSERT(declarator != nullptr);
695 ASSERT(declarator->getAsSymbolNode() != nullptr ||
696 (declarator->getAsBinaryNode() != nullptr &&
697 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
698 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300699 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100700 mDeclarators.push_back(declarator);
701}
702
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300703bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
704{
705 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
706 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
707 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
708 return false;
709}
710
Olli Etuaho57961272016-09-14 13:57:46 +0300711bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400712{
713 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100714 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
715 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400716 return false;
717}
718
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500719bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200720{
721 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100722 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300723 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200724 return false;
725}
726
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500727bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200728{
729 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
730 return false;
731}
732
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200733TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode()
Olli Etuahod7a25242015-08-18 13:49:45 +0300734{
735 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
736 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200737 // We need to manually copy any fields of TIntermNode.
Olli Etuahod7a25242015-08-18 13:49:45 +0300738 mLine = node.mLine;
739}
740
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200741bool TIntermTyped::hasConstantValue() const
Olli Etuahod4f4c112016-04-15 15:11:24 +0300742{
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200743 return false;
744}
745
746const TConstantUnion *TIntermTyped::getConstantValue() const
747{
748 return nullptr;
Olli Etuahod4f4c112016-04-15 15:11:24 +0300749}
750
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200751TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node)
752 : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300753{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200754 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300755}
756
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200757TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200758 : TIntermTyped(), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100759{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200760 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100761}
762
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200763const TType &TIntermFunctionPrototype::getType() const
764{
765 return mFunction->getReturnType();
766}
767
Olli Etuahod7a25242015-08-18 13:49:45 +0300768TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
769 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300770 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100771 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400772 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300773{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800774 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300775 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800776 TIntermTyped *typedArg = arg->getAsTyped();
777 ASSERT(typedArg != nullptr);
778 TIntermTyped *argCopy = typedArg->deepCopy();
779 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300780 }
781}
782
Olli Etuahofe486322017-03-21 09:30:54 +0000783TIntermAggregate *TIntermAggregate::shallowCopy() const
784{
785 TIntermSequence *copySeq = new TIntermSequence();
786 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400787 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000788 copyNode->setLine(mLine);
789 return copyNode;
790}
791
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200792TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermExpression(node)
Olli Etuahob6fa0432016-09-28 16:28:05 +0100793{
794 TIntermTyped *operandCopy = node.mOperand->deepCopy();
795 ASSERT(operandCopy != nullptr);
796 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000797 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob1de5a72018-03-28 14:07:57 +0300798 mHasFoldedDuplicateOffsets = node.mHasFoldedDuplicateOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100799}
800
Olli Etuahod7a25242015-08-18 13:49:45 +0300801TIntermBinary::TIntermBinary(const TIntermBinary &node)
802 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
803{
804 TIntermTyped *leftCopy = node.mLeft->deepCopy();
805 TIntermTyped *rightCopy = node.mRight->deepCopy();
806 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
807 mLeft = leftCopy;
808 mRight = rightCopy;
809}
810
811TIntermUnary::TIntermUnary(const TIntermUnary &node)
Olli Etuaho5fec7ab2018-04-04 11:58:33 +0300812 : TIntermOperator(node),
813 mUseEmulatedFunction(node.mUseEmulatedFunction),
814 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300815{
816 TIntermTyped *operandCopy = node.mOperand->deepCopy();
817 ASSERT(operandCopy != nullptr);
818 mOperand = operandCopy;
819}
820
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200821TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300822{
Olli Etuahod7a25242015-08-18 13:49:45 +0300823 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300824 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
825 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300826 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300827 mCondition = conditionCopy;
828 mTrueExpression = trueCopy;
829 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300830}
831
Jamie Madillb1a85f42014-08-19 15:23:24 -0400832bool TIntermOperator::isAssignment() const
833{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300834 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400835}
836
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300837bool TIntermOperator::isMultiplication() const
838{
839 switch (mOp)
840 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500841 case EOpMul:
842 case EOpMatrixTimesMatrix:
843 case EOpMatrixTimesVector:
844 case EOpMatrixTimesScalar:
845 case EOpVectorTimesMatrix:
846 case EOpVectorTimesScalar:
847 return true;
848 default:
849 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300850 }
851}
852
Jamie Madillb1a85f42014-08-19 15:23:24 -0400853bool TIntermOperator::isConstructor() const
854{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300855 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400856}
857
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800858bool TIntermOperator::isFunctionCall() const
859{
860 switch (mOp)
861 {
862 case EOpCallFunctionInAST:
863 case EOpCallBuiltInFunction:
864 case EOpCallInternalRawFunction:
865 return true;
866 default:
867 return false;
868 }
869}
870
Olli Etuaho1dded802016-08-18 18:13:13 +0300871TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
872{
873 if (left.isMatrix())
874 {
875 if (right.isMatrix())
876 {
877 return EOpMatrixTimesMatrix;
878 }
879 else
880 {
881 if (right.isVector())
882 {
883 return EOpMatrixTimesVector;
884 }
885 else
886 {
887 return EOpMatrixTimesScalar;
888 }
889 }
890 }
891 else
892 {
893 if (right.isMatrix())
894 {
895 if (left.isVector())
896 {
897 return EOpVectorTimesMatrix;
898 }
899 else
900 {
901 return EOpMatrixTimesScalar;
902 }
903 }
904 else
905 {
906 // Neither operand is a matrix.
907 if (left.isVector() == right.isVector())
908 {
909 // Leave as component product.
910 return EOpMul;
911 }
912 else
913 {
914 return EOpVectorTimesScalar;
915 }
916 }
917 }
918}
919
920TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
921{
922 if (left.isMatrix())
923 {
924 if (right.isMatrix())
925 {
926 return EOpMatrixTimesMatrixAssign;
927 }
928 else
929 {
930 // right should be scalar, but this may not be validated yet.
931 return EOpMatrixTimesScalarAssign;
932 }
933 }
934 else
935 {
936 if (right.isMatrix())
937 {
938 // Left should be a vector, but this may not be validated yet.
939 return EOpVectorTimesMatrixAssign;
940 }
941 else
942 {
943 // Neither operand is a matrix.
944 if (left.isVector() == right.isVector())
945 {
946 // Leave as component product.
947 return EOpMulAssign;
948 }
949 else
950 {
951 // left should be vector and right should be scalar, but this may not be validated
952 // yet.
953 return EOpVectorTimesScalarAssign;
954 }
955 }
956 }
957}
958
Jamie Madillb1a85f42014-08-19 15:23:24 -0400959//
960// Make sure the type of a unary operator is appropriate for its
961// combination of operation and operand type.
962//
Olli Etuahoa2234302016-08-31 12:05:39 +0300963void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400964{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300965 if (mOp == EOpArrayLength)
966 {
967 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
968 setType(TType(EbtInt, EbpUndefined, EvqConst));
969 return;
970 }
971
Olli Etuahoa2234302016-08-31 12:05:39 +0300972 TQualifier resultQualifier = EvqTemporary;
973 if (mOperand->getQualifier() == EvqConst)
974 resultQualifier = EvqConst;
975
976 unsigned char operandPrimarySize =
977 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400978 switch (mOp)
979 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300980 case EOpFloatBitsToInt:
981 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
982 break;
983 case EOpFloatBitsToUint:
984 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
985 break;
986 case EOpIntBitsToFloat:
987 case EOpUintBitsToFloat:
988 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
989 break;
990 case EOpPackSnorm2x16:
991 case EOpPackUnorm2x16:
992 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800993 case EOpPackUnorm4x8:
994 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300995 setType(TType(EbtUInt, EbpHigh, resultQualifier));
996 break;
997 case EOpUnpackSnorm2x16:
998 case EOpUnpackUnorm2x16:
999 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
1000 break;
1001 case EOpUnpackHalf2x16:
1002 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
1003 break;
Olli Etuaho25aef452017-01-29 16:15:44 -08001004 case EOpUnpackUnorm4x8:
1005 case EOpUnpackSnorm4x8:
1006 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
1007 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001008 case EOpAny:
1009 case EOpAll:
1010 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1011 break;
1012 case EOpLength:
1013 case EOpDeterminant:
1014 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
1015 break;
1016 case EOpTranspose:
1017 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
1018 static_cast<unsigned char>(mOperand->getType().getRows()),
1019 static_cast<unsigned char>(mOperand->getType().getCols())));
1020 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001021 case EOpIsinf:
1022 case EOpIsnan:
Olli Etuahoa2234302016-08-31 12:05:39 +03001023 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
1024 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001025 case EOpBitfieldReverse:
1026 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
1027 break;
1028 case EOpBitCount:
1029 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1030 break;
1031 case EOpFindLSB:
1032 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1033 break;
1034 case EOpFindMSB:
1035 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1036 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001037 default:
1038 setType(mOperand->getType());
1039 mType.setQualifier(resultQualifier);
1040 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001041 }
Olli Etuahoa2234302016-08-31 12:05:39 +03001042}
Jamie Madillb1a85f42014-08-19 15:23:24 -04001043
Olli Etuahob6fa0432016-09-28 16:28:05 +01001044TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001045 : TIntermExpression(TType(EbtFloat, EbpUndefined)),
Olli Etuahob6fa0432016-09-28 16:28:05 +01001046 mOperand(operand),
Olli Etuahob1de5a72018-03-28 14:07:57 +03001047 mSwizzleOffsets(swizzleOffsets),
1048 mHasFoldedDuplicateOffsets(false)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001049{
1050 ASSERT(mSwizzleOffsets.size() <= 4);
1051 promote();
1052}
1053
Olli Etuaho5fec7ab2018-04-04 11:58:33 +03001054TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function)
1055 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false), mFunction(function)
Olli Etuahoa2234302016-08-31 12:05:39 +03001056{
1057 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001058}
1059
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001060TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1061 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
1062{
1063 promote();
1064}
1065
Olli Etuaho0e99b7a2018-01-12 12:05:48 +02001066TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left,
1067 TIntermTyped *right,
1068 int shaderVersion)
1069{
1070 TIntermBinary *node = new TIntermBinary(EOpComma, left, right);
1071 node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right));
1072 return node;
1073}
1074
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001075TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1076 : TIntermNode(), mSymbol(symbol)
1077{
1078 ASSERT(symbol);
1079 setLine(line);
1080}
1081
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001082TIntermTernary::TIntermTernary(TIntermTyped *cond,
1083 TIntermTyped *trueExpression,
1084 TIntermTyped *falseExpression)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001085 : TIntermExpression(trueExpression->getType()),
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001086 mCondition(cond),
1087 mTrueExpression(trueExpression),
1088 mFalseExpression(falseExpression)
1089{
1090 getTypePointer()->setQualifier(
1091 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1092}
1093
Olli Etuaho81629262017-04-19 11:56:01 +03001094TIntermLoop::TIntermLoop(TLoopType type,
1095 TIntermNode *init,
1096 TIntermTyped *cond,
1097 TIntermTyped *expr,
1098 TIntermBlock *body)
1099 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1100{
1101 // Declaration nodes with no children can appear if all the declarators just added constants to
1102 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1103 if (mInit && mInit->getAsDeclarationNode() &&
1104 mInit->getAsDeclarationNode()->getSequence()->empty())
1105 {
1106 mInit = nullptr;
1107 }
1108}
1109
Olli Etuaho923ecef2017-10-11 12:01:38 +03001110TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
1111 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
1112{
1113 // Prune empty false blocks so that there won't be unnecessary operations done on it.
1114 if (mFalseBlock && mFalseBlock->getSequence()->empty())
1115 {
1116 mFalseBlock = nullptr;
1117 }
1118}
1119
1120TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
1121 : TIntermNode(), mInit(init), mStatementList(statementList)
1122{
1123 ASSERT(mStatementList);
1124}
1125
1126void TIntermSwitch::setStatementList(TIntermBlock *statementList)
1127{
1128 ASSERT(statementList);
1129 mStatementList = statementList;
1130}
1131
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001132// static
1133TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1134 TIntermTyped *trueExpression,
1135 TIntermTyped *falseExpression)
1136{
1137 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1138 falseExpression->getQualifier() == EvqConst)
1139 {
1140 return EvqConst;
1141 }
1142 return EvqTemporary;
1143}
1144
Olli Etuaho765924f2018-01-04 12:48:36 +02001145TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001146{
1147 if (mCondition->getAsConstantUnion())
1148 {
1149 if (mCondition->getAsConstantUnion()->getBConst(0))
1150 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001151 return mTrueExpression;
1152 }
1153 else
1154 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001155 return mFalseExpression;
1156 }
1157 }
1158 return this;
1159}
1160
Olli Etuahob6fa0432016-09-28 16:28:05 +01001161void TIntermSwizzle::promote()
1162{
1163 TQualifier resultQualifier = EvqTemporary;
1164 if (mOperand->getQualifier() == EvqConst)
1165 resultQualifier = EvqConst;
1166
1167 auto numFields = mSwizzleOffsets.size();
1168 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1169 static_cast<unsigned char>(numFields)));
1170}
1171
1172bool TIntermSwizzle::hasDuplicateOffsets() const
1173{
Olli Etuahob1de5a72018-03-28 14:07:57 +03001174 if (mHasFoldedDuplicateOffsets)
1175 {
1176 return true;
1177 }
Olli Etuahob6fa0432016-09-28 16:28:05 +01001178 int offsetCount[4] = {0u, 0u, 0u, 0u};
1179 for (const auto offset : mSwizzleOffsets)
1180 {
1181 offsetCount[offset]++;
1182 if (offsetCount[offset] > 1)
1183 {
1184 return true;
1185 }
1186 }
1187 return false;
1188}
1189
Olli Etuahob1de5a72018-03-28 14:07:57 +03001190void TIntermSwizzle::setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets)
1191{
1192 mHasFoldedDuplicateOffsets = hasFoldedDuplicateOffsets;
1193}
1194
Olli Etuaho09b04a22016-12-15 13:30:26 +00001195bool TIntermSwizzle::offsetsMatch(int offset) const
1196{
1197 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1198}
1199
Olli Etuahob6fa0432016-09-28 16:28:05 +01001200void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1201{
1202 for (const int offset : mSwizzleOffsets)
1203 {
1204 switch (offset)
1205 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001206 case 0:
1207 *out << "x";
1208 break;
1209 case 1:
1210 *out << "y";
1211 break;
1212 case 2:
1213 *out << "z";
1214 break;
1215 case 3:
1216 *out << "w";
1217 break;
1218 default:
1219 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001220 }
1221 }
1222}
1223
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001224TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1225 const TIntermTyped *left,
1226 const TIntermTyped *right)
1227{
1228 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1229 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1230 right->getQualifier() != EvqConst)
1231 {
1232 return EvqTemporary;
1233 }
1234 return EvqConst;
1235}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001236
1237// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001238void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001239{
Olli Etuaho1dded802016-08-18 18:13:13 +03001240 ASSERT(!isMultiplication() ||
1241 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1242
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001243 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1244 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001245 if (mOp == EOpComma)
1246 {
1247 setType(mRight->getType());
1248 return;
1249 }
1250
Jamie Madillb1a85f42014-08-19 15:23:24 -04001251 // Base assumption: just make the type the same as the left
1252 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001253 setType(mLeft->getType());
1254
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001255 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001256 // Binary operations results in temporary variables unless both
1257 // operands are const.
1258 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1259 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001260 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001261 getTypePointer()->setQualifier(EvqTemporary);
1262 }
1263
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001264 // Handle indexing ops.
1265 switch (mOp)
1266 {
1267 case EOpIndexDirect:
1268 case EOpIndexIndirect:
1269 if (mLeft->isArray())
1270 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001271 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001272 }
1273 else if (mLeft->isMatrix())
1274 {
1275 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1276 static_cast<unsigned char>(mLeft->getRows())));
1277 }
1278 else if (mLeft->isVector())
1279 {
1280 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1281 }
1282 else
1283 {
1284 UNREACHABLE();
1285 }
1286 return;
1287 case EOpIndexDirectStruct:
1288 {
1289 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1290 const int i = mRight->getAsConstantUnion()->getIConst(0);
1291 setType(*fields[i]->type());
1292 getTypePointer()->setQualifier(resultQualifier);
1293 return;
1294 }
1295 case EOpIndexDirectInterfaceBlock:
1296 {
1297 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1298 const int i = mRight->getAsConstantUnion()->getIConst(0);
1299 setType(*fields[i]->type());
1300 getTypePointer()->setQualifier(resultQualifier);
1301 return;
1302 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001303 default:
1304 break;
1305 }
1306
1307 ASSERT(mLeft->isArray() == mRight->isArray());
1308
1309 // The result gets promoted to the highest precision.
1310 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1311 getTypePointer()->setPrecision(higherPrecision);
1312
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001313 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001314
1315 //
1316 // All scalars or structs. Code after this test assumes this case is removed!
1317 //
1318 if (nominalSize == 1)
1319 {
1320 switch (mOp)
1321 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001322 //
1323 // Promote to conditional
1324 //
1325 case EOpEqual:
1326 case EOpNotEqual:
1327 case EOpLessThan:
1328 case EOpGreaterThan:
1329 case EOpLessThanEqual:
1330 case EOpGreaterThanEqual:
1331 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1332 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001333
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001334 //
1335 // And and Or operate on conditionals
1336 //
1337 case EOpLogicalAnd:
1338 case EOpLogicalXor:
1339 case EOpLogicalOr:
1340 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1341 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1342 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001343
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001344 default:
1345 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001346 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001347 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001348 }
1349
1350 // If we reach here, at least one of the operands is vector or matrix.
1351 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001352 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001353
Jamie Madillb1a85f42014-08-19 15:23:24 -04001354 switch (mOp)
1355 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001356 case EOpMul:
1357 break;
1358 case EOpMatrixTimesScalar:
1359 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001360 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001361 setType(TType(basicType, higherPrecision, resultQualifier,
1362 static_cast<unsigned char>(mRight->getCols()),
1363 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001364 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001365 break;
1366 case EOpMatrixTimesVector:
1367 setType(TType(basicType, higherPrecision, resultQualifier,
1368 static_cast<unsigned char>(mLeft->getRows()), 1));
1369 break;
1370 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001371 setType(TType(basicType, higherPrecision, resultQualifier,
1372 static_cast<unsigned char>(mRight->getCols()),
1373 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001374 break;
1375 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001376 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001377 static_cast<unsigned char>(nominalSize), 1));
1378 break;
1379 case EOpVectorTimesMatrix:
1380 setType(TType(basicType, higherPrecision, resultQualifier,
1381 static_cast<unsigned char>(mRight->getCols()), 1));
1382 break;
1383 case EOpMulAssign:
1384 case EOpVectorTimesScalarAssign:
1385 case EOpVectorTimesMatrixAssign:
1386 case EOpMatrixTimesScalarAssign:
1387 case EOpMatrixTimesMatrixAssign:
1388 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1389 break;
1390 case EOpAssign:
1391 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001392 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1393 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1394 break;
1395 case EOpAdd:
1396 case EOpSub:
1397 case EOpDiv:
1398 case EOpIMod:
1399 case EOpBitShiftLeft:
1400 case EOpBitShiftRight:
1401 case EOpBitwiseAnd:
1402 case EOpBitwiseXor:
1403 case EOpBitwiseOr:
1404 case EOpAddAssign:
1405 case EOpSubAssign:
1406 case EOpDivAssign:
1407 case EOpIModAssign:
1408 case EOpBitShiftLeftAssign:
1409 case EOpBitShiftRightAssign:
1410 case EOpBitwiseAndAssign:
1411 case EOpBitwiseXorAssign:
1412 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001413 {
1414 const int secondarySize =
1415 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1416 setType(TType(basicType, higherPrecision, resultQualifier,
1417 static_cast<unsigned char>(nominalSize),
1418 static_cast<unsigned char>(secondarySize)));
1419 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001420 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001421 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001422 case EOpEqual:
1423 case EOpNotEqual:
1424 case EOpLessThan:
1425 case EOpGreaterThan:
1426 case EOpLessThanEqual:
1427 case EOpGreaterThanEqual:
1428 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1429 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001430 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001431 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001432
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001433 case EOpIndexDirect:
1434 case EOpIndexIndirect:
1435 case EOpIndexDirectInterfaceBlock:
1436 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001437 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001438 UNREACHABLE();
1439 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001440 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001441 UNREACHABLE();
1442 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001443 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001444}
1445
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001446bool TIntermConstantUnion::hasConstantValue() const
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001447{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001448 return true;
1449}
1450
1451const TConstantUnion *TIntermConstantUnion::getConstantValue() const
1452{
1453 return mUnionArrayPointer;
1454}
1455
1456const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
1457 const TConstantUnion *constArray,
1458 int index)
1459{
1460 if (type.isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001461 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001462 ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
1463 TType arrayElementType(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001464 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001465 size_t arrayElementSize = arrayElementType.getObjectSize();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001466 return &constArray[arrayElementSize * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001467 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001468 else if (type.isMatrix())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001469 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001470 ASSERT(index < type.getCols());
1471 int size = type.getRows();
1472 return &constArray[size * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001473 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001474 else if (type.isVector())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001475 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001476 ASSERT(index < type.getNominalSize());
1477 return &constArray[index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001478 }
1479 else
1480 {
1481 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001482 return nullptr;
1483 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001484}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001485
Olli Etuaho765924f2018-01-04 12:48:36 +02001486TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001487{
Olli Etuahob1de5a72018-03-28 14:07:57 +03001488 TIntermSwizzle *operandSwizzle = mOperand->getAsSwizzleNode();
1489 if (operandSwizzle)
1490 {
1491 // We need to fold the two swizzles into one, so that repeated swizzling can't cause stack
1492 // overflow in ParseContext::checkCanBeLValue().
1493 bool hadDuplicateOffsets = operandSwizzle->hasDuplicateOffsets();
1494 TVector<int> foldedOffsets;
1495 for (int offset : mSwizzleOffsets)
1496 {
1497 // Offset should already be validated.
1498 ASSERT(static_cast<size_t>(offset) < operandSwizzle->mSwizzleOffsets.size());
1499 foldedOffsets.push_back(operandSwizzle->mSwizzleOffsets[offset]);
1500 }
1501 operandSwizzle->mSwizzleOffsets = foldedOffsets;
1502 operandSwizzle->setType(getType());
1503 operandSwizzle->setHasFoldedDuplicateOffsets(hadDuplicateOffsets);
1504 return operandSwizzle;
1505 }
Olli Etuahob6fa0432016-09-28 16:28:05 +01001506 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1507 if (operandConstant == nullptr)
1508 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001509 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001510 }
1511
1512 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1513 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1514 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001515 constArray[i] = *TIntermConstantUnion::FoldIndexing(
1516 operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
Olli Etuahob6fa0432016-09-28 16:28:05 +01001517 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001518 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001519}
1520
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001521TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1522{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001523 const TConstantUnion *rightConstant = mRight->getConstantValue();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001524 switch (mOp)
1525 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001526 case EOpComma:
1527 {
1528 if (mLeft->hasSideEffects())
1529 {
1530 return this;
1531 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001532 return mRight;
1533 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001534 case EOpIndexDirect:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001535 case EOpIndexDirectStruct:
1536 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001537 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001538 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001539 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001540 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001541 size_t index = static_cast<size_t>(rightConstant->getIConst());
1542 TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
1543 if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
1544 !leftAggregate->hasSideEffects())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001545 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001546 ASSERT(index < leftAggregate->getSequence()->size());
1547 // This transformation can't add complexity as we're eliminating the constructor
1548 // entirely.
1549 return leftAggregate->getSequence()->at(index)->getAsTyped();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001550 }
1551
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001552 // If the indexed value is already a constant union, we can't increase duplication of
1553 // data by folding the indexing. Also fold the node in case it's generally beneficial to
1554 // replace this type of node with a constant union even if that would mean duplicating
1555 // data.
1556 if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
1557 {
1558 const TConstantUnion *constantValue = getConstantValue();
1559 if (constantValue == nullptr)
1560 {
1561 return this;
1562 }
1563 return CreateFoldedNode(constantValue, this);
1564 }
1565 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001566 }
1567 case EOpIndexIndirect:
1568 case EOpIndexDirectInterfaceBlock:
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001569 case EOpInitialize:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001570 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001571 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001572 default:
1573 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001574 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001575 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001576 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001577 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001578 const TConstantUnion *leftConstant = mLeft->getConstantValue();
1579 if (leftConstant == nullptr)
1580 {
1581 return this;
1582 }
1583 const TConstantUnion *constArray =
1584 TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
1585 mRight->getType(), diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001586 if (!constArray)
1587 {
1588 return this;
1589 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001590 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001591 }
1592 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001593}
1594
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001595bool TIntermBinary::hasConstantValue() const
1596{
1597 switch (mOp)
1598 {
1599 case EOpIndexDirect:
1600 case EOpIndexDirectStruct:
1601 {
1602 if (mLeft->hasConstantValue() && mRight->hasConstantValue())
1603 {
1604 return true;
1605 }
Nico Weber41b072b2018-02-09 10:01:32 -05001606 break;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001607 }
1608 default:
1609 break;
1610 }
1611 return false;
1612}
1613
1614const TConstantUnion *TIntermBinary::getConstantValue() const
1615{
1616 if (!hasConstantValue())
1617 {
1618 return nullptr;
1619 }
1620
1621 const TConstantUnion *leftConstantValue = mLeft->getConstantValue();
1622 int index = mRight->getConstantValue()->getIConst();
1623 const TConstantUnion *constIndexingResult = nullptr;
1624 if (mOp == EOpIndexDirect)
1625 {
1626 constIndexingResult =
1627 TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
1628 }
1629 else
1630 {
1631 ASSERT(mOp == EOpIndexDirectStruct);
1632 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1633
1634 size_t previousFieldsSize = 0;
1635 for (int i = 0; i < index; ++i)
1636 {
1637 previousFieldsSize += fields[i]->type()->getObjectSize();
1638 }
1639 constIndexingResult = leftConstantValue + previousFieldsSize;
1640 }
1641 return constIndexingResult;
1642}
1643
Olli Etuahof119a262016-08-19 15:54:22 +03001644TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001645{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301646 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001647
1648 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301649 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001650 // The size of runtime-sized arrays may only be determined at runtime.
1651 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001652 {
1653 return this;
1654 }
1655 constArray = new TConstantUnion[1];
1656 constArray->setIConst(mOperand->getOutermostArraySize());
1657 }
1658 else
1659 {
1660 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1661 if (operandConstant == nullptr)
1662 {
1663 return this;
1664 }
1665
1666 switch (mOp)
1667 {
1668 case EOpAny:
1669 case EOpAll:
1670 case EOpLength:
1671 case EOpTranspose:
1672 case EOpDeterminant:
1673 case EOpInverse:
1674 case EOpPackSnorm2x16:
1675 case EOpUnpackSnorm2x16:
1676 case EOpPackUnorm2x16:
1677 case EOpUnpackUnorm2x16:
1678 case EOpPackHalf2x16:
1679 case EOpUnpackHalf2x16:
1680 case EOpPackUnorm4x8:
1681 case EOpPackSnorm4x8:
1682 case EOpUnpackUnorm4x8:
1683 case EOpUnpackSnorm4x8:
1684 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1685 break;
1686 default:
1687 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1688 break;
1689 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301690 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001691 if (constArray == nullptr)
1692 {
1693 return this;
1694 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001695 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001696}
1697
Olli Etuahof119a262016-08-19 15:54:22 +03001698TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001699{
1700 // Make sure that all params are constant before actual constant folding.
1701 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001702 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001703 if (param->getAsConstantUnion() == nullptr)
1704 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001705 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001706 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001707 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001708 const TConstantUnion *constArray = nullptr;
Olli Etuaho1d122782015-11-06 15:35:17 +02001709 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001710 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001711 if (mType.canReplaceWithConstantUnion())
Olli Etuaho765924f2018-01-04 12:48:36 +02001712 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001713 constArray = getConstantValue();
Olli Etuaho765924f2018-01-04 12:48:36 +02001714 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001715 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001716 else if (CanFoldAggregateBuiltInOp(mOp))
Olli Etuaho2768bc82017-12-12 11:51:48 +02001717 {
Olli Etuahof119a262016-08-19 15:54:22 +03001718 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001719 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001720 if (constArray == nullptr)
1721 {
1722 return this;
1723 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001724 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001725}
1726
Jamie Madillb1a85f42014-08-19 15:23:24 -04001727//
1728// The fold functions see if an operation on a constant can be done in place,
1729// without generating run-time code.
1730//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001731// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001732//
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001733const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
1734 const TConstantUnion *leftArray,
1735 const TType &leftType,
1736 const TConstantUnion *rightArray,
1737 const TType &rightType,
1738 TDiagnostics *diagnostics,
1739 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001740{
Olli Etuahof119a262016-08-19 15:54:22 +03001741 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001742
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001743 size_t objectSize = leftType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001744
1745 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001746 if (rightType.getObjectSize() == 1 && objectSize > 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001747 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001748 rightArray = Vectorize(*rightArray, objectSize);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001749 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001750 else if (rightType.getObjectSize() > 1 && objectSize == 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001751 {
1752 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001753 leftArray = Vectorize(*leftArray, rightType.getObjectSize());
1754 objectSize = rightType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001755 }
1756
1757 TConstantUnion *resultArray = nullptr;
1758
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001759 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001760 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001761 case EOpAdd:
1762 resultArray = new TConstantUnion[objectSize];
1763 for (size_t i = 0; i < objectSize; i++)
1764 resultArray[i] =
1765 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1766 break;
1767 case EOpSub:
1768 resultArray = new TConstantUnion[objectSize];
1769 for (size_t i = 0; i < objectSize; i++)
1770 resultArray[i] =
1771 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1772 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001773
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001774 case EOpMul:
1775 case EOpVectorTimesScalar:
1776 case EOpMatrixTimesScalar:
1777 resultArray = new TConstantUnion[objectSize];
1778 for (size_t i = 0; i < objectSize; i++)
1779 resultArray[i] =
1780 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1781 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001782
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001783 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001784 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001785 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001786 ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001787
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001788 const int leftCols = leftType.getCols();
1789 const int leftRows = leftType.getRows();
1790 const int rightCols = rightType.getCols();
1791 const int rightRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001792 const int resultCols = rightCols;
1793 const int resultRows = leftRows;
1794
1795 resultArray = new TConstantUnion[resultCols * resultRows];
1796 for (int row = 0; row < resultRows; row++)
1797 {
1798 for (int column = 0; column < resultCols; column++)
1799 {
1800 resultArray[resultRows * column + row].setFConst(0.0f);
1801 for (int i = 0; i < leftCols; i++)
1802 {
1803 resultArray[resultRows * column + row].setFConst(
1804 resultArray[resultRows * column + row].getFConst() +
1805 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001806 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001807 }
1808 }
1809 }
1810 }
1811 break;
1812
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001813 case EOpDiv:
1814 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001815 {
1816 resultArray = new TConstantUnion[objectSize];
1817 for (size_t i = 0; i < objectSize; i++)
1818 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001819 switch (leftType.getBasicType())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001820 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001821 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001822 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001823 ASSERT(op == EOpDiv);
1824 float dividend = leftArray[i].getFConst();
1825 float divisor = rightArray[i].getFConst();
1826 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001827 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001828 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001829 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001830 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001831 line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001832 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001833 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001834 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001835 }
1836 else
1837 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001838 diagnostics->warning(line, "Divide by zero during constant folding",
1839 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001840 bool negativeResult =
1841 std::signbit(dividend) != std::signbit(divisor);
1842 resultArray[i].setFConst(
1843 negativeResult ? -std::numeric_limits<float>::infinity()
1844 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001845 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001846 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001847 else if (gl::isInf(dividend) && gl::isInf(divisor))
1848 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001849 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001850 "Infinity divided by infinity during constant "
1851 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001852 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001853 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1854 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001855 else
1856 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001857 float result = dividend / divisor;
1858 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001859 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001860 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001861 line, "Constant folded division overflowed to infinity", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001862 }
1863 resultArray[i].setFConst(result);
1864 }
1865 break;
1866 }
1867 case EbtInt:
1868 if (rightArray[i] == 0)
1869 {
1870 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001871 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001872 resultArray[i].setIConst(INT_MAX);
1873 }
1874 else
1875 {
1876 int lhs = leftArray[i].getIConst();
1877 int divisor = rightArray[i].getIConst();
1878 if (op == EOpDiv)
1879 {
1880 // Check for the special case where the minimum representable number
1881 // is
1882 // divided by -1. If left alone this leads to integer overflow in
1883 // C++.
1884 // ESSL 3.00.6 section 4.1.3 Integers:
1885 // "However, for the case where the minimum representable value is
1886 // divided by -1, it is allowed to return either the minimum
1887 // representable value or the maximum representable value."
1888 if (lhs == -0x7fffffff - 1 && divisor == -1)
1889 {
1890 resultArray[i].setIConst(0x7fffffff);
1891 }
1892 else
1893 {
1894 resultArray[i].setIConst(lhs / divisor);
1895 }
Olli Etuahod4453572016-09-27 13:21:46 +01001896 }
1897 else
1898 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001899 ASSERT(op == EOpIMod);
1900 if (lhs < 0 || divisor < 0)
1901 {
1902 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1903 // when
1904 // either one of the operands is negative.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001905 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001906 "Negative modulus operator operand "
1907 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001908 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001909 resultArray[i].setIConst(0);
1910 }
1911 else
1912 {
1913 resultArray[i].setIConst(lhs % divisor);
1914 }
Olli Etuahod4453572016-09-27 13:21:46 +01001915 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001916 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001917 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001918
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001919 case EbtUInt:
1920 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001921 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001922 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001923 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001924 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001925 }
1926 else
1927 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001928 if (op == EOpDiv)
1929 {
1930 resultArray[i].setUConst(leftArray[i].getUConst() /
1931 rightArray[i].getUConst());
1932 }
1933 else
1934 {
1935 ASSERT(op == EOpIMod);
1936 resultArray[i].setUConst(leftArray[i].getUConst() %
1937 rightArray[i].getUConst());
1938 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001939 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001940 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001941
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001942 default:
1943 UNREACHABLE();
1944 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001945 }
1946 }
1947 }
1948 break;
1949
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001950 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001951 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001952 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001953 ASSERT(rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001954
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001955 const int matrixCols = leftType.getCols();
1956 const int matrixRows = leftType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001957
1958 resultArray = new TConstantUnion[matrixRows];
1959
1960 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1961 {
1962 resultArray[matrixRow].setFConst(0.0f);
1963 for (int col = 0; col < matrixCols; col++)
1964 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001965 resultArray[matrixRow].setFConst(
1966 resultArray[matrixRow].getFConst() +
1967 leftArray[col * matrixRows + matrixRow].getFConst() *
1968 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001969 }
1970 }
1971 }
1972 break;
1973
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001974 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001975 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001976 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001977 ASSERT(leftType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001978
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001979 const int matrixCols = rightType.getCols();
1980 const int matrixRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001981
1982 resultArray = new TConstantUnion[matrixCols];
1983
1984 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1985 {
1986 resultArray[matrixCol].setFConst(0.0f);
1987 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1988 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001989 resultArray[matrixCol].setFConst(
1990 resultArray[matrixCol].getFConst() +
1991 leftArray[matrixRow].getFConst() *
1992 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001993 }
1994 }
1995 }
1996 break;
1997
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001998 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001999 {
2000 resultArray = new TConstantUnion[objectSize];
2001 for (size_t i = 0; i < objectSize; i++)
2002 {
2003 resultArray[i] = leftArray[i] && rightArray[i];
2004 }
2005 }
2006 break;
2007
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002008 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002009 {
2010 resultArray = new TConstantUnion[objectSize];
2011 for (size_t i = 0; i < objectSize; i++)
2012 {
2013 resultArray[i] = leftArray[i] || rightArray[i];
2014 }
2015 }
2016 break;
2017
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002018 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002019 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002020 ASSERT(leftType.getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002021 resultArray = new TConstantUnion[objectSize];
2022 for (size_t i = 0; i < objectSize; i++)
2023 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03002024 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002025 }
2026 }
2027 break;
2028
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002029 case EOpBitwiseAnd:
2030 resultArray = new TConstantUnion[objectSize];
2031 for (size_t i = 0; i < objectSize; i++)
2032 resultArray[i] = leftArray[i] & rightArray[i];
2033 break;
2034 case EOpBitwiseXor:
2035 resultArray = new TConstantUnion[objectSize];
2036 for (size_t i = 0; i < objectSize; i++)
2037 resultArray[i] = leftArray[i] ^ rightArray[i];
2038 break;
2039 case EOpBitwiseOr:
2040 resultArray = new TConstantUnion[objectSize];
2041 for (size_t i = 0; i < objectSize; i++)
2042 resultArray[i] = leftArray[i] | rightArray[i];
2043 break;
2044 case EOpBitShiftLeft:
2045 resultArray = new TConstantUnion[objectSize];
2046 for (size_t i = 0; i < objectSize; i++)
2047 resultArray[i] =
2048 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
2049 break;
2050 case EOpBitShiftRight:
2051 resultArray = new TConstantUnion[objectSize];
2052 for (size_t i = 0; i < objectSize; i++)
2053 resultArray[i] =
2054 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
2055 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002056
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002057 case EOpLessThan:
2058 ASSERT(objectSize == 1);
2059 resultArray = new TConstantUnion[1];
2060 resultArray->setBConst(*leftArray < *rightArray);
2061 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002062
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002063 case EOpGreaterThan:
2064 ASSERT(objectSize == 1);
2065 resultArray = new TConstantUnion[1];
2066 resultArray->setBConst(*leftArray > *rightArray);
2067 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002068
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002069 case EOpLessThanEqual:
2070 ASSERT(objectSize == 1);
2071 resultArray = new TConstantUnion[1];
2072 resultArray->setBConst(!(*leftArray > *rightArray));
2073 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002074
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002075 case EOpGreaterThanEqual:
2076 ASSERT(objectSize == 1);
2077 resultArray = new TConstantUnion[1];
2078 resultArray->setBConst(!(*leftArray < *rightArray));
2079 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002080
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002081 case EOpEqual:
2082 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002083 {
2084 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002085 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002086 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002087 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002088 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002089 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002090 equal = false;
2091 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002092 }
2093 }
2094 if (op == EOpEqual)
2095 {
2096 resultArray->setBConst(equal);
2097 }
2098 else
2099 {
2100 resultArray->setBConst(!equal);
2101 }
2102 }
2103 break;
2104
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002105 default:
2106 UNREACHABLE();
2107 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002108 }
2109 return resultArray;
2110}
2111
Olli Etuahof119a262016-08-19 15:54:22 +03002112// The fold functions do operations on a constant at GLSL compile time, without generating run-time
2113// code. Returns the constant value to keep using. Nullptr should not be returned.
2114TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04002115{
Olli Etuahof119a262016-08-19 15:54:22 +03002116 // Do operations where the return type may have a different number of components compared to the
2117 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04002118
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002119 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002120 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302121
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002122 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302123 TConstantUnion *resultArray = nullptr;
2124 switch (op)
2125 {
Olli Etuahof119a262016-08-19 15:54:22 +03002126 case EOpAny:
2127 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302128 resultArray = new TConstantUnion();
2129 resultArray->setBConst(false);
2130 for (size_t i = 0; i < objectSize; i++)
2131 {
2132 if (operandArray[i].getBConst())
2133 {
2134 resultArray->setBConst(true);
2135 break;
2136 }
2137 }
2138 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302139
Olli Etuahof119a262016-08-19 15:54:22 +03002140 case EOpAll:
2141 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302142 resultArray = new TConstantUnion();
2143 resultArray->setBConst(true);
2144 for (size_t i = 0; i < objectSize; i++)
2145 {
2146 if (!operandArray[i].getBConst())
2147 {
2148 resultArray->setBConst(false);
2149 break;
2150 }
2151 }
2152 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302153
Olli Etuahof119a262016-08-19 15:54:22 +03002154 case EOpLength:
2155 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302156 resultArray = new TConstantUnion();
2157 resultArray->setFConst(VectorLength(operandArray, objectSize));
2158 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302159
Olli Etuahof119a262016-08-19 15:54:22 +03002160 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302161 {
Olli Etuahof119a262016-08-19 15:54:22 +03002162 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302163 resultArray = new TConstantUnion[objectSize];
2164 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002165 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302166 SetUnionArrayFromMatrix(result, resultArray);
2167 break;
2168 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302169
Olli Etuahof119a262016-08-19 15:54:22 +03002170 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302171 {
Olli Etuahof119a262016-08-19 15:54:22 +03002172 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302173 unsigned int size = getType().getNominalSize();
2174 ASSERT(size >= 2 && size <= 4);
2175 resultArray = new TConstantUnion();
2176 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
2177 break;
2178 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302179
Olli Etuahof119a262016-08-19 15:54:22 +03002180 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302181 {
Olli Etuahof119a262016-08-19 15:54:22 +03002182 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302183 unsigned int size = getType().getNominalSize();
2184 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03002185 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05302186 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
2187 SetUnionArrayFromMatrix(result, resultArray);
2188 break;
2189 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302190
Olli Etuahof119a262016-08-19 15:54:22 +03002191 case EOpPackSnorm2x16:
2192 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302193 ASSERT(getType().getNominalSize() == 2);
2194 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002195 resultArray->setUConst(
2196 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302197 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302198
Olli Etuahof119a262016-08-19 15:54:22 +03002199 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302200 {
Olli Etuahof119a262016-08-19 15:54:22 +03002201 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302202 resultArray = new TConstantUnion[2];
2203 float f1, f2;
2204 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2205 resultArray[0].setFConst(f1);
2206 resultArray[1].setFConst(f2);
2207 break;
2208 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302209
Olli Etuahof119a262016-08-19 15:54:22 +03002210 case EOpPackUnorm2x16:
2211 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302212 ASSERT(getType().getNominalSize() == 2);
2213 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002214 resultArray->setUConst(
2215 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302216 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302217
Olli Etuahof119a262016-08-19 15:54:22 +03002218 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302219 {
Olli Etuahof119a262016-08-19 15:54:22 +03002220 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302221 resultArray = new TConstantUnion[2];
2222 float f1, f2;
2223 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2224 resultArray[0].setFConst(f1);
2225 resultArray[1].setFConst(f2);
2226 break;
2227 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302228
Olli Etuahof119a262016-08-19 15:54:22 +03002229 case EOpPackHalf2x16:
2230 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302231 ASSERT(getType().getNominalSize() == 2);
2232 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002233 resultArray->setUConst(
2234 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302235 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302236
Olli Etuahof119a262016-08-19 15:54:22 +03002237 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302238 {
Olli Etuahof119a262016-08-19 15:54:22 +03002239 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302240 resultArray = new TConstantUnion[2];
2241 float f1, f2;
2242 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2243 resultArray[0].setFConst(f1);
2244 resultArray[1].setFConst(f2);
2245 break;
2246 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302247
Olli Etuaho25aef452017-01-29 16:15:44 -08002248 case EOpPackUnorm4x8:
2249 {
2250 ASSERT(getType().getBasicType() == EbtFloat);
2251 resultArray = new TConstantUnion();
2252 resultArray->setUConst(
2253 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2254 operandArray[2].getFConst(), operandArray[3].getFConst()));
2255 break;
2256 }
2257 case EOpPackSnorm4x8:
2258 {
2259 ASSERT(getType().getBasicType() == EbtFloat);
2260 resultArray = new TConstantUnion();
2261 resultArray->setUConst(
2262 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2263 operandArray[2].getFConst(), operandArray[3].getFConst()));
2264 break;
2265 }
2266 case EOpUnpackUnorm4x8:
2267 {
2268 ASSERT(getType().getBasicType() == EbtUInt);
2269 resultArray = new TConstantUnion[4];
2270 float f[4];
2271 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2272 for (size_t i = 0; i < 4; ++i)
2273 {
2274 resultArray[i].setFConst(f[i]);
2275 }
2276 break;
2277 }
2278 case EOpUnpackSnorm4x8:
2279 {
2280 ASSERT(getType().getBasicType() == EbtUInt);
2281 resultArray = new TConstantUnion[4];
2282 float f[4];
2283 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2284 for (size_t i = 0; i < 4; ++i)
2285 {
2286 resultArray[i].setFConst(f[i]);
2287 }
2288 break;
2289 }
2290
Olli Etuahof119a262016-08-19 15:54:22 +03002291 default:
2292 UNREACHABLE();
2293 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302294 }
2295
2296 return resultArray;
2297}
2298
Olli Etuahof119a262016-08-19 15:54:22 +03002299TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2300 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302301{
Olli Etuahof119a262016-08-19 15:54:22 +03002302 // Do unary operations where each component of the result is computed based on the corresponding
2303 // component of the operand. Also folds normalize, though the divisor in that case takes all
2304 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302305
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002306 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002307 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002308
2309 size_t objectSize = getType().getObjectSize();
2310
Arun Patoleab2b9a22015-07-06 18:27:56 +05302311 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2312 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302313 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002314 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302315 {
Olli Etuahof119a262016-08-19 15:54:22 +03002316 case EOpNegative:
2317 switch (getType().getBasicType())
2318 {
2319 case EbtFloat:
2320 resultArray[i].setFConst(-operandArray[i].getFConst());
2321 break;
2322 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002323 if (operandArray[i] == std::numeric_limits<int>::min())
2324 {
2325 // The minimum representable integer doesn't have a positive
2326 // counterpart, rather the negation overflows and in ESSL is supposed to
2327 // wrap back to the minimum representable integer. Make sure that we
2328 // don't actually let the negation overflow, which has undefined
2329 // behavior in C++.
2330 resultArray[i].setIConst(std::numeric_limits<int>::min());
2331 }
2332 else
2333 {
2334 resultArray[i].setIConst(-operandArray[i].getIConst());
2335 }
Olli Etuahof119a262016-08-19 15:54:22 +03002336 break;
2337 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002338 if (operandArray[i] == 0x80000000u)
2339 {
2340 resultArray[i].setUConst(0x80000000u);
2341 }
2342 else
2343 {
2344 resultArray[i].setUConst(static_cast<unsigned int>(
2345 -static_cast<int>(operandArray[i].getUConst())));
2346 }
Olli Etuahof119a262016-08-19 15:54:22 +03002347 break;
2348 default:
2349 UNREACHABLE();
2350 return nullptr;
2351 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302352 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302353
Olli Etuahof119a262016-08-19 15:54:22 +03002354 case EOpPositive:
2355 switch (getType().getBasicType())
2356 {
2357 case EbtFloat:
2358 resultArray[i].setFConst(operandArray[i].getFConst());
2359 break;
2360 case EbtInt:
2361 resultArray[i].setIConst(operandArray[i].getIConst());
2362 break;
2363 case EbtUInt:
2364 resultArray[i].setUConst(static_cast<unsigned int>(
2365 static_cast<int>(operandArray[i].getUConst())));
2366 break;
2367 default:
2368 UNREACHABLE();
2369 return nullptr;
2370 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302371 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302372
Olli Etuahof119a262016-08-19 15:54:22 +03002373 case EOpLogicalNot:
2374 switch (getType().getBasicType())
2375 {
2376 case EbtBool:
2377 resultArray[i].setBConst(!operandArray[i].getBConst());
2378 break;
2379 default:
2380 UNREACHABLE();
2381 return nullptr;
2382 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302383 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302384
Olli Etuahof119a262016-08-19 15:54:22 +03002385 case EOpBitwiseNot:
2386 switch (getType().getBasicType())
2387 {
2388 case EbtInt:
2389 resultArray[i].setIConst(~operandArray[i].getIConst());
2390 break;
2391 case EbtUInt:
2392 resultArray[i].setUConst(~operandArray[i].getUConst());
2393 break;
2394 default:
2395 UNREACHABLE();
2396 return nullptr;
2397 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302398 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302399
Olli Etuahof119a262016-08-19 15:54:22 +03002400 case EOpRadians:
2401 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302402 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2403 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302404
Olli Etuahof119a262016-08-19 15:54:22 +03002405 case EOpDegrees:
2406 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302407 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2408 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302409
Olli Etuahof119a262016-08-19 15:54:22 +03002410 case EOpSin:
2411 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302412 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302413
Olli Etuahof119a262016-08-19 15:54:22 +03002414 case EOpCos:
2415 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2416 break;
2417
2418 case EOpTan:
2419 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2420 break;
2421
2422 case EOpAsin:
2423 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2424 // 0.
2425 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2426 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2427 diagnostics, &resultArray[i]);
2428 else
2429 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2430 break;
2431
2432 case EOpAcos:
2433 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2434 // 0.
2435 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2436 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2437 diagnostics, &resultArray[i]);
2438 else
2439 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2440 break;
2441
2442 case EOpAtan:
2443 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2444 break;
2445
2446 case EOpSinh:
2447 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2448 break;
2449
2450 case EOpCosh:
2451 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2452 break;
2453
2454 case EOpTanh:
2455 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2456 break;
2457
2458 case EOpAsinh:
2459 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2460 break;
2461
2462 case EOpAcosh:
2463 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2464 if (operandArray[i].getFConst() < 1.0f)
2465 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2466 diagnostics, &resultArray[i]);
2467 else
2468 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2469 break;
2470
2471 case EOpAtanh:
2472 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2473 // 0.
2474 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2475 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2476 diagnostics, &resultArray[i]);
2477 else
2478 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2479 break;
2480
2481 case EOpAbs:
2482 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302483 {
Olli Etuahof119a262016-08-19 15:54:22 +03002484 case EbtFloat:
2485 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2486 break;
2487 case EbtInt:
2488 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2489 break;
2490 default:
2491 UNREACHABLE();
2492 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302493 }
2494 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002495
2496 case EOpSign:
2497 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302498 {
Olli Etuahof119a262016-08-19 15:54:22 +03002499 case EbtFloat:
2500 {
2501 float fConst = operandArray[i].getFConst();
2502 float fResult = 0.0f;
2503 if (fConst > 0.0f)
2504 fResult = 1.0f;
2505 else if (fConst < 0.0f)
2506 fResult = -1.0f;
2507 resultArray[i].setFConst(fResult);
2508 break;
2509 }
2510 case EbtInt:
2511 {
2512 int iConst = operandArray[i].getIConst();
2513 int iResult = 0;
2514 if (iConst > 0)
2515 iResult = 1;
2516 else if (iConst < 0)
2517 iResult = -1;
2518 resultArray[i].setIConst(iResult);
2519 break;
2520 }
2521 default:
2522 UNREACHABLE();
2523 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302524 }
2525 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302526
Olli Etuahof119a262016-08-19 15:54:22 +03002527 case EOpFloor:
2528 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2529 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302530
Olli Etuahof119a262016-08-19 15:54:22 +03002531 case EOpTrunc:
2532 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2533 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302534
Olli Etuahof119a262016-08-19 15:54:22 +03002535 case EOpRound:
2536 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2537 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302538
Olli Etuahof119a262016-08-19 15:54:22 +03002539 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302540 {
Olli Etuahof119a262016-08-19 15:54:22 +03002541 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302542 float x = operandArray[i].getFConst();
2543 float result;
2544 float fractPart = modff(x, &result);
2545 if (fabsf(fractPart) == 0.5f)
2546 result = 2.0f * roundf(x / 2.0f);
2547 else
2548 result = roundf(x);
2549 resultArray[i].setFConst(result);
2550 break;
2551 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302552
Olli Etuahof119a262016-08-19 15:54:22 +03002553 case EOpCeil:
2554 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2555 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302556
Olli Etuahof119a262016-08-19 15:54:22 +03002557 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302558 {
Olli Etuahof119a262016-08-19 15:54:22 +03002559 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302560 float x = operandArray[i].getFConst();
2561 resultArray[i].setFConst(x - floorf(x));
2562 break;
2563 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302564
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002565 case EOpIsnan:
Olli Etuahof119a262016-08-19 15:54:22 +03002566 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302567 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2568 break;
Arun Patole551279e2015-07-07 18:18:23 +05302569
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002570 case EOpIsinf:
Olli Etuahof119a262016-08-19 15:54:22 +03002571 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302572 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2573 break;
Arun Patole551279e2015-07-07 18:18:23 +05302574
Olli Etuahof119a262016-08-19 15:54:22 +03002575 case EOpFloatBitsToInt:
2576 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302577 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2578 break;
Arun Patole551279e2015-07-07 18:18:23 +05302579
Olli Etuahof119a262016-08-19 15:54:22 +03002580 case EOpFloatBitsToUint:
2581 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302582 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2583 break;
Arun Patole551279e2015-07-07 18:18:23 +05302584
Olli Etuahof119a262016-08-19 15:54:22 +03002585 case EOpIntBitsToFloat:
2586 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302587 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2588 break;
Arun Patole551279e2015-07-07 18:18:23 +05302589
Olli Etuahof119a262016-08-19 15:54:22 +03002590 case EOpUintBitsToFloat:
2591 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302592 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2593 break;
Arun Patole551279e2015-07-07 18:18:23 +05302594
Olli Etuahof119a262016-08-19 15:54:22 +03002595 case EOpExp:
2596 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2597 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302598
Olli Etuahof119a262016-08-19 15:54:22 +03002599 case EOpLog:
2600 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2601 if (operandArray[i].getFConst() <= 0.0f)
2602 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2603 diagnostics, &resultArray[i]);
2604 else
2605 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2606 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302607
Olli Etuahof119a262016-08-19 15:54:22 +03002608 case EOpExp2:
2609 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2610 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302611
Olli Etuahof119a262016-08-19 15:54:22 +03002612 case EOpLog2:
2613 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2614 // And log2f is not available on some plarforms like old android, so just using
2615 // log(x)/log(2) here.
2616 if (operandArray[i].getFConst() <= 0.0f)
2617 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2618 diagnostics, &resultArray[i]);
2619 else
2620 {
2621 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2622 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2623 }
2624 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302625
Olli Etuahof119a262016-08-19 15:54:22 +03002626 case EOpSqrt:
2627 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2628 if (operandArray[i].getFConst() < 0.0f)
2629 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2630 diagnostics, &resultArray[i]);
2631 else
2632 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2633 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302634
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002635 case EOpInversesqrt:
Olli Etuahof119a262016-08-19 15:54:22 +03002636 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2637 // so getting the square root first using builtin function sqrt() and then taking
2638 // its inverse.
2639 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2640 // result to 0.
2641 if (operandArray[i].getFConst() <= 0.0f)
2642 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2643 diagnostics, &resultArray[i]);
2644 else
2645 {
2646 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2647 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2648 }
2649 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302650
Olli Etuahod68924e2017-01-02 17:34:40 +00002651 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002652 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302653 resultArray[i].setBConst(!operandArray[i].getBConst());
2654 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302655
Olli Etuahof119a262016-08-19 15:54:22 +03002656 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302657 {
Olli Etuahof119a262016-08-19 15:54:22 +03002658 ASSERT(getType().getBasicType() == EbtFloat);
2659 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302660 float length = VectorLength(operandArray, objectSize);
2661 if (length)
2662 resultArray[i].setFConst(x / length);
2663 else
Olli Etuahof119a262016-08-19 15:54:22 +03002664 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2665 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302666 break;
2667 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002668 case EOpBitfieldReverse:
2669 {
2670 uint32_t value;
2671 if (getType().getBasicType() == EbtInt)
2672 {
2673 value = static_cast<uint32_t>(operandArray[i].getIConst());
2674 }
2675 else
2676 {
2677 ASSERT(getType().getBasicType() == EbtUInt);
2678 value = operandArray[i].getUConst();
2679 }
2680 uint32_t result = gl::BitfieldReverse(value);
2681 if (getType().getBasicType() == EbtInt)
2682 {
2683 resultArray[i].setIConst(static_cast<int32_t>(result));
2684 }
2685 else
2686 {
2687 resultArray[i].setUConst(result);
2688 }
2689 break;
2690 }
2691 case EOpBitCount:
2692 {
2693 uint32_t value;
2694 if (getType().getBasicType() == EbtInt)
2695 {
2696 value = static_cast<uint32_t>(operandArray[i].getIConst());
2697 }
2698 else
2699 {
2700 ASSERT(getType().getBasicType() == EbtUInt);
2701 value = operandArray[i].getUConst();
2702 }
2703 int result = gl::BitCount(value);
2704 resultArray[i].setIConst(result);
2705 break;
2706 }
2707 case EOpFindLSB:
2708 {
2709 uint32_t value;
2710 if (getType().getBasicType() == EbtInt)
2711 {
2712 value = static_cast<uint32_t>(operandArray[i].getIConst());
2713 }
2714 else
2715 {
2716 ASSERT(getType().getBasicType() == EbtUInt);
2717 value = operandArray[i].getUConst();
2718 }
2719 resultArray[i].setIConst(gl::FindLSB(value));
2720 break;
2721 }
2722 case EOpFindMSB:
2723 {
2724 uint32_t value;
2725 if (getType().getBasicType() == EbtInt)
2726 {
2727 int intValue = operandArray[i].getIConst();
2728 value = static_cast<uint32_t>(intValue);
2729 if (intValue < 0)
2730 {
2731 // Look for zero instead of one in value. This also handles the intValue ==
2732 // -1 special case, where the return value needs to be -1.
2733 value = ~value;
2734 }
2735 }
2736 else
2737 {
2738 ASSERT(getType().getBasicType() == EbtUInt);
2739 value = operandArray[i].getUConst();
2740 }
2741 resultArray[i].setIConst(gl::FindMSB(value));
2742 break;
2743 }
Olli Etuahof119a262016-08-19 15:54:22 +03002744 case EOpDFdx:
2745 case EOpDFdy:
2746 case EOpFwidth:
2747 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302748 // Derivatives of constant arguments should be 0.
2749 resultArray[i].setFConst(0.0f);
2750 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302751
Olli Etuahof119a262016-08-19 15:54:22 +03002752 default:
2753 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302754 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302755 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002756
Arun Patoleab2b9a22015-07-06 18:27:56 +05302757 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002758}
2759
Olli Etuahof119a262016-08-19 15:54:22 +03002760void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2761 FloatTypeUnaryFunc builtinFunc,
2762 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302763{
2764 ASSERT(builtinFunc);
2765
Olli Etuahof119a262016-08-19 15:54:22 +03002766 ASSERT(getType().getBasicType() == EbtFloat);
2767 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302768}
2769
Jamie Madillb1a85f42014-08-19 15:23:24 -04002770// static
Olli Etuahof119a262016-08-19 15:54:22 +03002771TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2772 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302773{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002774 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002775 TIntermSequence *arguments = aggregate->getSequence();
2776 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2777 std::vector<const TConstantUnion *> unionArrays(argsCount);
2778 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002779 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302780 TBasicType basicType = EbtVoid;
2781 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002782 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302783 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002784 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2785 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302786
2787 if (i == 0)
2788 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002789 basicType = argConstant->getType().getBasicType();
2790 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302791 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002792 unionArrays[i] = argConstant->getConstantValue();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002793 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002794 if (objectSizes[i] > maxObjectSize)
2795 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302796 }
2797
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002798 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302799 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002800 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302801 if (objectSizes[i] != maxObjectSize)
2802 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2803 }
Arun Patole274f0702015-05-05 13:33:30 +05302804
Olli Etuahob43846e2015-06-02 18:18:57 +03002805 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002806
2807 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302808 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002809 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302810 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002811 ASSERT(basicType == EbtFloat);
2812 resultArray = new TConstantUnion[maxObjectSize];
2813 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302814 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002815 float y = unionArrays[0][i].getFConst();
2816 float x = unionArrays[1][i].getFConst();
2817 // Results are undefined if x and y are both 0.
2818 if (x == 0.0f && y == 0.0f)
2819 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2820 else
2821 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302822 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002823 break;
2824 }
Arun Patolebf790422015-05-18 17:53:04 +05302825
Olli Etuaho51182ab2017-01-22 00:12:29 +00002826 case EOpPow:
2827 {
2828 ASSERT(basicType == EbtFloat);
2829 resultArray = new TConstantUnion[maxObjectSize];
2830 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302831 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002832 float x = unionArrays[0][i].getFConst();
2833 float y = unionArrays[1][i].getFConst();
2834 // Results are undefined if x < 0.
2835 // Results are undefined if x = 0 and y <= 0.
2836 if (x < 0.0f)
2837 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2838 else if (x == 0.0f && y <= 0.0f)
2839 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2840 else
2841 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302842 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002843 break;
2844 }
Arun Patolebf790422015-05-18 17:53:04 +05302845
Olli Etuaho51182ab2017-01-22 00:12:29 +00002846 case EOpMod:
2847 {
2848 ASSERT(basicType == EbtFloat);
2849 resultArray = new TConstantUnion[maxObjectSize];
2850 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302851 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002852 float x = unionArrays[0][i].getFConst();
2853 float y = unionArrays[1][i].getFConst();
2854 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302855 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002856 break;
2857 }
Arun Patolebf790422015-05-18 17:53:04 +05302858
Olli Etuaho51182ab2017-01-22 00:12:29 +00002859 case EOpMin:
2860 {
2861 resultArray = new TConstantUnion[maxObjectSize];
2862 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302863 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002864 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302865 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002866 case EbtFloat:
2867 resultArray[i].setFConst(
2868 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2869 break;
2870 case EbtInt:
2871 resultArray[i].setIConst(
2872 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2873 break;
2874 case EbtUInt:
2875 resultArray[i].setUConst(
2876 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2877 break;
2878 default:
2879 UNREACHABLE();
2880 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302881 }
2882 }
2883 break;
Arun Patole274f0702015-05-05 13:33:30 +05302884 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002885
2886 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302887 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002888 resultArray = new TConstantUnion[maxObjectSize];
2889 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302890 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002891 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302892 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002893 case EbtFloat:
2894 resultArray[i].setFConst(
2895 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2896 break;
2897 case EbtInt:
2898 resultArray[i].setIConst(
2899 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2900 break;
2901 case EbtUInt:
2902 resultArray[i].setUConst(
2903 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2904 break;
2905 default:
2906 UNREACHABLE();
2907 break;
Arun Patole274f0702015-05-05 13:33:30 +05302908 }
2909 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002910 break;
Arun Patole274f0702015-05-05 13:33:30 +05302911 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002912
2913 case EOpStep:
2914 {
2915 ASSERT(basicType == EbtFloat);
2916 resultArray = new TConstantUnion[maxObjectSize];
2917 for (size_t i = 0; i < maxObjectSize; i++)
2918 resultArray[i].setFConst(
2919 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2920 break;
2921 }
2922
2923 case EOpLessThanComponentWise:
2924 {
2925 resultArray = new TConstantUnion[maxObjectSize];
2926 for (size_t i = 0; i < maxObjectSize; i++)
2927 {
2928 switch (basicType)
2929 {
2930 case EbtFloat:
2931 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2932 unionArrays[1][i].getFConst());
2933 break;
2934 case EbtInt:
2935 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2936 unionArrays[1][i].getIConst());
2937 break;
2938 case EbtUInt:
2939 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2940 unionArrays[1][i].getUConst());
2941 break;
2942 default:
2943 UNREACHABLE();
2944 break;
2945 }
2946 }
2947 break;
2948 }
2949
2950 case EOpLessThanEqualComponentWise:
2951 {
2952 resultArray = new TConstantUnion[maxObjectSize];
2953 for (size_t i = 0; i < maxObjectSize; i++)
2954 {
2955 switch (basicType)
2956 {
2957 case EbtFloat:
2958 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2959 unionArrays[1][i].getFConst());
2960 break;
2961 case EbtInt:
2962 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2963 unionArrays[1][i].getIConst());
2964 break;
2965 case EbtUInt:
2966 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2967 unionArrays[1][i].getUConst());
2968 break;
2969 default:
2970 UNREACHABLE();
2971 break;
2972 }
2973 }
2974 break;
2975 }
2976
2977 case EOpGreaterThanComponentWise:
2978 {
2979 resultArray = new TConstantUnion[maxObjectSize];
2980 for (size_t i = 0; i < maxObjectSize; i++)
2981 {
2982 switch (basicType)
2983 {
2984 case EbtFloat:
2985 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2986 unionArrays[1][i].getFConst());
2987 break;
2988 case EbtInt:
2989 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2990 unionArrays[1][i].getIConst());
2991 break;
2992 case EbtUInt:
2993 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2994 unionArrays[1][i].getUConst());
2995 break;
2996 default:
2997 UNREACHABLE();
2998 break;
2999 }
3000 }
3001 break;
3002 }
3003 case EOpGreaterThanEqualComponentWise:
3004 {
3005 resultArray = new TConstantUnion[maxObjectSize];
3006 for (size_t i = 0; i < maxObjectSize; i++)
3007 {
3008 switch (basicType)
3009 {
3010 case EbtFloat:
3011 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
3012 unionArrays[1][i].getFConst());
3013 break;
3014 case EbtInt:
3015 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
3016 unionArrays[1][i].getIConst());
3017 break;
3018 case EbtUInt:
3019 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
3020 unionArrays[1][i].getUConst());
3021 break;
3022 default:
3023 UNREACHABLE();
3024 break;
3025 }
3026 }
3027 }
3028 break;
3029
3030 case EOpEqualComponentWise:
3031 {
3032 resultArray = new TConstantUnion[maxObjectSize];
3033 for (size_t i = 0; i < maxObjectSize; i++)
3034 {
3035 switch (basicType)
3036 {
3037 case EbtFloat:
3038 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
3039 unionArrays[1][i].getFConst());
3040 break;
3041 case EbtInt:
3042 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
3043 unionArrays[1][i].getIConst());
3044 break;
3045 case EbtUInt:
3046 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
3047 unionArrays[1][i].getUConst());
3048 break;
3049 case EbtBool:
3050 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
3051 unionArrays[1][i].getBConst());
3052 break;
3053 default:
3054 UNREACHABLE();
3055 break;
3056 }
3057 }
3058 break;
3059 }
3060
3061 case EOpNotEqualComponentWise:
3062 {
3063 resultArray = new TConstantUnion[maxObjectSize];
3064 for (size_t i = 0; i < maxObjectSize; i++)
3065 {
3066 switch (basicType)
3067 {
3068 case EbtFloat:
3069 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
3070 unionArrays[1][i].getFConst());
3071 break;
3072 case EbtInt:
3073 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3074 unionArrays[1][i].getIConst());
3075 break;
3076 case EbtUInt:
3077 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3078 unionArrays[1][i].getUConst());
3079 break;
3080 case EbtBool:
3081 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3082 unionArrays[1][i].getBConst());
3083 break;
3084 default:
3085 UNREACHABLE();
3086 break;
3087 }
3088 }
3089 break;
3090 }
3091
3092 case EOpDistance:
3093 {
3094 ASSERT(basicType == EbtFloat);
3095 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3096 resultArray = new TConstantUnion();
3097 for (size_t i = 0; i < maxObjectSize; i++)
3098 {
3099 float x = unionArrays[0][i].getFConst();
3100 float y = unionArrays[1][i].getFConst();
3101 distanceArray[i].setFConst(x - y);
3102 }
3103 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3104 break;
3105 }
3106
3107 case EOpDot:
3108 ASSERT(basicType == EbtFloat);
3109 resultArray = new TConstantUnion();
3110 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3111 break;
3112
3113 case EOpCross:
3114 {
3115 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3116 resultArray = new TConstantUnion[maxObjectSize];
3117 float x0 = unionArrays[0][0].getFConst();
3118 float x1 = unionArrays[0][1].getFConst();
3119 float x2 = unionArrays[0][2].getFConst();
3120 float y0 = unionArrays[1][0].getFConst();
3121 float y1 = unionArrays[1][1].getFConst();
3122 float y2 = unionArrays[1][2].getFConst();
3123 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3124 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3125 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3126 break;
3127 }
3128
3129 case EOpReflect:
3130 {
3131 ASSERT(basicType == EbtFloat);
3132 // genType reflect (genType I, genType N) :
3133 // For the incident vector I and surface orientation N, returns the reflection
3134 // direction:
3135 // I - 2 * dot(N, I) * N.
3136 resultArray = new TConstantUnion[maxObjectSize];
3137 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3138 for (size_t i = 0; i < maxObjectSize; i++)
3139 {
3140 float result = unionArrays[0][i].getFConst() -
3141 2.0f * dotProduct * unionArrays[1][i].getFConst();
3142 resultArray[i].setFConst(result);
3143 }
3144 break;
3145 }
3146
3147 case EOpMulMatrixComponentWise:
3148 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003149 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3150 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003151 // Perform component-wise matrix multiplication.
3152 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003153 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003154 angle::Matrix<float> result =
3155 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3156 SetUnionArrayFromMatrix(result, resultArray);
3157 break;
3158 }
3159
3160 case EOpOuterProduct:
3161 {
3162 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003163 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3164 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003165 resultArray = new TConstantUnion[numRows * numCols];
3166 angle::Matrix<float> result =
3167 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3168 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3169 SetUnionArrayFromMatrix(result, resultArray);
3170 break;
3171 }
3172
3173 case EOpClamp:
3174 {
3175 resultArray = new TConstantUnion[maxObjectSize];
3176 for (size_t i = 0; i < maxObjectSize; i++)
3177 {
3178 switch (basicType)
3179 {
3180 case EbtFloat:
3181 {
3182 float x = unionArrays[0][i].getFConst();
3183 float min = unionArrays[1][i].getFConst();
3184 float max = unionArrays[2][i].getFConst();
3185 // Results are undefined if min > max.
3186 if (min > max)
3187 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3188 &resultArray[i]);
3189 else
3190 resultArray[i].setFConst(gl::clamp(x, min, max));
3191 break;
3192 }
3193
3194 case EbtInt:
3195 {
3196 int x = unionArrays[0][i].getIConst();
3197 int min = unionArrays[1][i].getIConst();
3198 int max = unionArrays[2][i].getIConst();
3199 // Results are undefined if min > max.
3200 if (min > max)
3201 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3202 &resultArray[i]);
3203 else
3204 resultArray[i].setIConst(gl::clamp(x, min, max));
3205 break;
3206 }
3207 case EbtUInt:
3208 {
3209 unsigned int x = unionArrays[0][i].getUConst();
3210 unsigned int min = unionArrays[1][i].getUConst();
3211 unsigned int max = unionArrays[2][i].getUConst();
3212 // Results are undefined if min > max.
3213 if (min > max)
3214 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3215 &resultArray[i]);
3216 else
3217 resultArray[i].setUConst(gl::clamp(x, min, max));
3218 break;
3219 }
3220 default:
3221 UNREACHABLE();
3222 break;
3223 }
3224 }
3225 break;
3226 }
3227
3228 case EOpMix:
3229 {
3230 ASSERT(basicType == EbtFloat);
3231 resultArray = new TConstantUnion[maxObjectSize];
3232 for (size_t i = 0; i < maxObjectSize; i++)
3233 {
3234 float x = unionArrays[0][i].getFConst();
3235 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003236 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003237 if (type == EbtFloat)
3238 {
3239 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3240 float a = unionArrays[2][i].getFConst();
3241 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3242 }
3243 else // 3rd parameter is EbtBool
3244 {
3245 ASSERT(type == EbtBool);
3246 // Selects which vector each returned component comes from.
3247 // For a component of a that is false, the corresponding component of x is
3248 // returned.
3249 // For a component of a that is true, the corresponding component of y is
3250 // returned.
3251 bool a = unionArrays[2][i].getBConst();
3252 resultArray[i].setFConst(a ? y : x);
3253 }
3254 }
3255 break;
3256 }
3257
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02003258 case EOpSmoothstep:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003259 {
3260 ASSERT(basicType == EbtFloat);
3261 resultArray = new TConstantUnion[maxObjectSize];
3262 for (size_t i = 0; i < maxObjectSize; i++)
3263 {
3264 float edge0 = unionArrays[0][i].getFConst();
3265 float edge1 = unionArrays[1][i].getFConst();
3266 float x = unionArrays[2][i].getFConst();
3267 // Results are undefined if edge0 >= edge1.
3268 if (edge0 >= edge1)
3269 {
3270 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3271 }
3272 else
3273 {
3274 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3275 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3276 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3277 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3278 }
3279 }
3280 break;
3281 }
3282
Olli Etuaho74da73f2017-02-01 15:37:48 +00003283 case EOpLdexp:
3284 {
3285 resultArray = new TConstantUnion[maxObjectSize];
3286 for (size_t i = 0; i < maxObjectSize; i++)
3287 {
3288 float x = unionArrays[0][i].getFConst();
3289 int exp = unionArrays[1][i].getIConst();
3290 if (exp > 128)
3291 {
3292 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3293 }
3294 else
3295 {
3296 resultArray[i].setFConst(gl::Ldexp(x, exp));
3297 }
3298 }
3299 break;
3300 }
3301
Jamie Madille72595b2017-06-06 15:12:26 -04003302 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003303 {
3304 ASSERT(basicType == EbtFloat);
3305 // genType faceforward(genType N, genType I, genType Nref) :
3306 // If dot(Nref, I) < 0 return N, otherwise return -N.
3307 resultArray = new TConstantUnion[maxObjectSize];
3308 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3309 for (size_t i = 0; i < maxObjectSize; i++)
3310 {
3311 if (dotProduct < 0)
3312 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3313 else
3314 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3315 }
3316 break;
3317 }
3318
3319 case EOpRefract:
3320 {
3321 ASSERT(basicType == EbtFloat);
3322 // genType refract(genType I, genType N, float eta) :
3323 // For the incident vector I and surface normal N, and the ratio of indices of
3324 // refraction eta,
3325 // return the refraction vector. The result is computed by
3326 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3327 // if (k < 0.0)
3328 // return genType(0.0)
3329 // else
3330 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3331 resultArray = new TConstantUnion[maxObjectSize];
3332 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3333 for (size_t i = 0; i < maxObjectSize; i++)
3334 {
3335 float eta = unionArrays[2][i].getFConst();
3336 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3337 if (k < 0.0f)
3338 resultArray[i].setFConst(0.0f);
3339 else
3340 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3341 (eta * dotProduct + sqrtf(k)) *
3342 unionArrays[1][i].getFConst());
3343 }
3344 break;
3345 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003346 case EOpBitfieldExtract:
3347 {
3348 resultArray = new TConstantUnion[maxObjectSize];
3349 for (size_t i = 0; i < maxObjectSize; ++i)
3350 {
3351 int offset = unionArrays[1][0].getIConst();
3352 int bits = unionArrays[2][0].getIConst();
3353 if (bits == 0)
3354 {
3355 if (aggregate->getBasicType() == EbtInt)
3356 {
3357 resultArray[i].setIConst(0);
3358 }
3359 else
3360 {
3361 ASSERT(aggregate->getBasicType() == EbtUInt);
3362 resultArray[i].setUConst(0);
3363 }
3364 }
3365 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3366 {
3367 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3368 &resultArray[i]);
3369 }
3370 else
3371 {
3372 // bits can be 32 here, so we need to avoid bit shift overflow.
3373 uint32_t maskMsb = 1u << (bits - 1);
3374 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3375 if (aggregate->getBasicType() == EbtInt)
3376 {
3377 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3378 uint32_t resultUnsigned = (value & mask) >> offset;
3379 if ((resultUnsigned & maskMsb) != 0)
3380 {
3381 // The most significant bits (from bits+1 to the most significant bit)
3382 // should be set to 1.
3383 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3384 resultUnsigned |= higherBitsMask;
3385 }
3386 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3387 }
3388 else
3389 {
3390 ASSERT(aggregate->getBasicType() == EbtUInt);
3391 uint32_t value = unionArrays[0][i].getUConst();
3392 resultArray[i].setUConst((value & mask) >> offset);
3393 }
3394 }
3395 }
3396 break;
3397 }
3398 case EOpBitfieldInsert:
3399 {
3400 resultArray = new TConstantUnion[maxObjectSize];
3401 for (size_t i = 0; i < maxObjectSize; ++i)
3402 {
3403 int offset = unionArrays[2][0].getIConst();
3404 int bits = unionArrays[3][0].getIConst();
3405 if (bits == 0)
3406 {
3407 if (aggregate->getBasicType() == EbtInt)
3408 {
3409 int32_t base = unionArrays[0][i].getIConst();
3410 resultArray[i].setIConst(base);
3411 }
3412 else
3413 {
3414 ASSERT(aggregate->getBasicType() == EbtUInt);
3415 uint32_t base = unionArrays[0][i].getUConst();
3416 resultArray[i].setUConst(base);
3417 }
3418 }
3419 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3420 {
3421 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3422 &resultArray[i]);
3423 }
3424 else
3425 {
3426 // bits can be 32 here, so we need to avoid bit shift overflow.
3427 uint32_t maskMsb = 1u << (bits - 1);
3428 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3429 uint32_t baseMask = ~insertMask;
3430 if (aggregate->getBasicType() == EbtInt)
3431 {
3432 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3433 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3434 uint32_t resultUnsigned =
3435 (base & baseMask) | ((insert << offset) & insertMask);
3436 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3437 }
3438 else
3439 {
3440 ASSERT(aggregate->getBasicType() == EbtUInt);
3441 uint32_t base = unionArrays[0][i].getUConst();
3442 uint32_t insert = unionArrays[1][i].getUConst();
3443 resultArray[i].setUConst((base & baseMask) |
3444 ((insert << offset) & insertMask));
3445 }
3446 }
3447 }
3448 break;
3449 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003450
3451 default:
3452 UNREACHABLE();
3453 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303454 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003455 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303456}
3457
Jamie Madill45bcc782016-11-07 13:58:48 -05003458} // namespace sh