blob: 4e25c442ad85d7c4acce26e08fcba66a961aa210 [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)
812 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
813{
814 TIntermTyped *operandCopy = node.mOperand->deepCopy();
815 ASSERT(operandCopy != nullptr);
816 mOperand = operandCopy;
817}
818
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200819TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300820{
Olli Etuahod7a25242015-08-18 13:49:45 +0300821 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300822 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
823 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300824 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300825 mCondition = conditionCopy;
826 mTrueExpression = trueCopy;
827 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300828}
829
Jamie Madillb1a85f42014-08-19 15:23:24 -0400830bool TIntermOperator::isAssignment() const
831{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300832 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400833}
834
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300835bool TIntermOperator::isMultiplication() const
836{
837 switch (mOp)
838 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500839 case EOpMul:
840 case EOpMatrixTimesMatrix:
841 case EOpMatrixTimesVector:
842 case EOpMatrixTimesScalar:
843 case EOpVectorTimesMatrix:
844 case EOpVectorTimesScalar:
845 return true;
846 default:
847 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300848 }
849}
850
Jamie Madillb1a85f42014-08-19 15:23:24 -0400851bool TIntermOperator::isConstructor() const
852{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300853 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400854}
855
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800856bool TIntermOperator::isFunctionCall() const
857{
858 switch (mOp)
859 {
860 case EOpCallFunctionInAST:
861 case EOpCallBuiltInFunction:
862 case EOpCallInternalRawFunction:
863 return true;
864 default:
865 return false;
866 }
867}
868
Olli Etuaho1dded802016-08-18 18:13:13 +0300869TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
870{
871 if (left.isMatrix())
872 {
873 if (right.isMatrix())
874 {
875 return EOpMatrixTimesMatrix;
876 }
877 else
878 {
879 if (right.isVector())
880 {
881 return EOpMatrixTimesVector;
882 }
883 else
884 {
885 return EOpMatrixTimesScalar;
886 }
887 }
888 }
889 else
890 {
891 if (right.isMatrix())
892 {
893 if (left.isVector())
894 {
895 return EOpVectorTimesMatrix;
896 }
897 else
898 {
899 return EOpMatrixTimesScalar;
900 }
901 }
902 else
903 {
904 // Neither operand is a matrix.
905 if (left.isVector() == right.isVector())
906 {
907 // Leave as component product.
908 return EOpMul;
909 }
910 else
911 {
912 return EOpVectorTimesScalar;
913 }
914 }
915 }
916}
917
918TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
919{
920 if (left.isMatrix())
921 {
922 if (right.isMatrix())
923 {
924 return EOpMatrixTimesMatrixAssign;
925 }
926 else
927 {
928 // right should be scalar, but this may not be validated yet.
929 return EOpMatrixTimesScalarAssign;
930 }
931 }
932 else
933 {
934 if (right.isMatrix())
935 {
936 // Left should be a vector, but this may not be validated yet.
937 return EOpVectorTimesMatrixAssign;
938 }
939 else
940 {
941 // Neither operand is a matrix.
942 if (left.isVector() == right.isVector())
943 {
944 // Leave as component product.
945 return EOpMulAssign;
946 }
947 else
948 {
949 // left should be vector and right should be scalar, but this may not be validated
950 // yet.
951 return EOpVectorTimesScalarAssign;
952 }
953 }
954 }
955}
956
Jamie Madillb1a85f42014-08-19 15:23:24 -0400957//
958// Make sure the type of a unary operator is appropriate for its
959// combination of operation and operand type.
960//
Olli Etuahoa2234302016-08-31 12:05:39 +0300961void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400962{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300963 if (mOp == EOpArrayLength)
964 {
965 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
966 setType(TType(EbtInt, EbpUndefined, EvqConst));
967 return;
968 }
969
Olli Etuahoa2234302016-08-31 12:05:39 +0300970 TQualifier resultQualifier = EvqTemporary;
971 if (mOperand->getQualifier() == EvqConst)
972 resultQualifier = EvqConst;
973
974 unsigned char operandPrimarySize =
975 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400976 switch (mOp)
977 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300978 case EOpFloatBitsToInt:
979 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
980 break;
981 case EOpFloatBitsToUint:
982 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
983 break;
984 case EOpIntBitsToFloat:
985 case EOpUintBitsToFloat:
986 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
987 break;
988 case EOpPackSnorm2x16:
989 case EOpPackUnorm2x16:
990 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800991 case EOpPackUnorm4x8:
992 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300993 setType(TType(EbtUInt, EbpHigh, resultQualifier));
994 break;
995 case EOpUnpackSnorm2x16:
996 case EOpUnpackUnorm2x16:
997 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
998 break;
999 case EOpUnpackHalf2x16:
1000 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
1001 break;
Olli Etuaho25aef452017-01-29 16:15:44 -08001002 case EOpUnpackUnorm4x8:
1003 case EOpUnpackSnorm4x8:
1004 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
1005 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001006 case EOpAny:
1007 case EOpAll:
1008 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1009 break;
1010 case EOpLength:
1011 case EOpDeterminant:
1012 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
1013 break;
1014 case EOpTranspose:
1015 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
1016 static_cast<unsigned char>(mOperand->getType().getRows()),
1017 static_cast<unsigned char>(mOperand->getType().getCols())));
1018 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001019 case EOpIsinf:
1020 case EOpIsnan:
Olli Etuahoa2234302016-08-31 12:05:39 +03001021 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
1022 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001023 case EOpBitfieldReverse:
1024 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
1025 break;
1026 case EOpBitCount:
1027 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1028 break;
1029 case EOpFindLSB:
1030 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1031 break;
1032 case EOpFindMSB:
1033 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1034 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001035 default:
1036 setType(mOperand->getType());
1037 mType.setQualifier(resultQualifier);
1038 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001039 }
Olli Etuahoa2234302016-08-31 12:05:39 +03001040}
Jamie Madillb1a85f42014-08-19 15:23:24 -04001041
Olli Etuahob6fa0432016-09-28 16:28:05 +01001042TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001043 : TIntermExpression(TType(EbtFloat, EbpUndefined)),
Olli Etuahob6fa0432016-09-28 16:28:05 +01001044 mOperand(operand),
Olli Etuahob1de5a72018-03-28 14:07:57 +03001045 mSwizzleOffsets(swizzleOffsets),
1046 mHasFoldedDuplicateOffsets(false)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001047{
1048 ASSERT(mSwizzleOffsets.size() <= 4);
1049 promote();
1050}
1051
Olli Etuahoa2234302016-08-31 12:05:39 +03001052TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
1053 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
1054{
1055 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001056}
1057
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001058TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1059 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
1060{
1061 promote();
1062}
1063
Olli Etuaho0e99b7a2018-01-12 12:05:48 +02001064TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left,
1065 TIntermTyped *right,
1066 int shaderVersion)
1067{
1068 TIntermBinary *node = new TIntermBinary(EOpComma, left, right);
1069 node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right));
1070 return node;
1071}
1072
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001073TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1074 : TIntermNode(), mSymbol(symbol)
1075{
1076 ASSERT(symbol);
1077 setLine(line);
1078}
1079
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001080TIntermTernary::TIntermTernary(TIntermTyped *cond,
1081 TIntermTyped *trueExpression,
1082 TIntermTyped *falseExpression)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001083 : TIntermExpression(trueExpression->getType()),
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001084 mCondition(cond),
1085 mTrueExpression(trueExpression),
1086 mFalseExpression(falseExpression)
1087{
1088 getTypePointer()->setQualifier(
1089 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1090}
1091
Olli Etuaho81629262017-04-19 11:56:01 +03001092TIntermLoop::TIntermLoop(TLoopType type,
1093 TIntermNode *init,
1094 TIntermTyped *cond,
1095 TIntermTyped *expr,
1096 TIntermBlock *body)
1097 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1098{
1099 // Declaration nodes with no children can appear if all the declarators just added constants to
1100 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1101 if (mInit && mInit->getAsDeclarationNode() &&
1102 mInit->getAsDeclarationNode()->getSequence()->empty())
1103 {
1104 mInit = nullptr;
1105 }
1106}
1107
Olli Etuaho923ecef2017-10-11 12:01:38 +03001108TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
1109 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
1110{
1111 // Prune empty false blocks so that there won't be unnecessary operations done on it.
1112 if (mFalseBlock && mFalseBlock->getSequence()->empty())
1113 {
1114 mFalseBlock = nullptr;
1115 }
1116}
1117
1118TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
1119 : TIntermNode(), mInit(init), mStatementList(statementList)
1120{
1121 ASSERT(mStatementList);
1122}
1123
1124void TIntermSwitch::setStatementList(TIntermBlock *statementList)
1125{
1126 ASSERT(statementList);
1127 mStatementList = statementList;
1128}
1129
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001130// static
1131TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1132 TIntermTyped *trueExpression,
1133 TIntermTyped *falseExpression)
1134{
1135 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1136 falseExpression->getQualifier() == EvqConst)
1137 {
1138 return EvqConst;
1139 }
1140 return EvqTemporary;
1141}
1142
Olli Etuaho765924f2018-01-04 12:48:36 +02001143TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001144{
1145 if (mCondition->getAsConstantUnion())
1146 {
1147 if (mCondition->getAsConstantUnion()->getBConst(0))
1148 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001149 return mTrueExpression;
1150 }
1151 else
1152 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001153 return mFalseExpression;
1154 }
1155 }
1156 return this;
1157}
1158
Olli Etuahob6fa0432016-09-28 16:28:05 +01001159void TIntermSwizzle::promote()
1160{
1161 TQualifier resultQualifier = EvqTemporary;
1162 if (mOperand->getQualifier() == EvqConst)
1163 resultQualifier = EvqConst;
1164
1165 auto numFields = mSwizzleOffsets.size();
1166 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1167 static_cast<unsigned char>(numFields)));
1168}
1169
1170bool TIntermSwizzle::hasDuplicateOffsets() const
1171{
Olli Etuahob1de5a72018-03-28 14:07:57 +03001172 if (mHasFoldedDuplicateOffsets)
1173 {
1174 return true;
1175 }
Olli Etuahob6fa0432016-09-28 16:28:05 +01001176 int offsetCount[4] = {0u, 0u, 0u, 0u};
1177 for (const auto offset : mSwizzleOffsets)
1178 {
1179 offsetCount[offset]++;
1180 if (offsetCount[offset] > 1)
1181 {
1182 return true;
1183 }
1184 }
1185 return false;
1186}
1187
Olli Etuahob1de5a72018-03-28 14:07:57 +03001188void TIntermSwizzle::setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets)
1189{
1190 mHasFoldedDuplicateOffsets = hasFoldedDuplicateOffsets;
1191}
1192
Olli Etuaho09b04a22016-12-15 13:30:26 +00001193bool TIntermSwizzle::offsetsMatch(int offset) const
1194{
1195 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1196}
1197
Olli Etuahob6fa0432016-09-28 16:28:05 +01001198void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1199{
1200 for (const int offset : mSwizzleOffsets)
1201 {
1202 switch (offset)
1203 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001204 case 0:
1205 *out << "x";
1206 break;
1207 case 1:
1208 *out << "y";
1209 break;
1210 case 2:
1211 *out << "z";
1212 break;
1213 case 3:
1214 *out << "w";
1215 break;
1216 default:
1217 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001218 }
1219 }
1220}
1221
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001222TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1223 const TIntermTyped *left,
1224 const TIntermTyped *right)
1225{
1226 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1227 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1228 right->getQualifier() != EvqConst)
1229 {
1230 return EvqTemporary;
1231 }
1232 return EvqConst;
1233}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001234
1235// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001236void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001237{
Olli Etuaho1dded802016-08-18 18:13:13 +03001238 ASSERT(!isMultiplication() ||
1239 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1240
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001241 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1242 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001243 if (mOp == EOpComma)
1244 {
1245 setType(mRight->getType());
1246 return;
1247 }
1248
Jamie Madillb1a85f42014-08-19 15:23:24 -04001249 // Base assumption: just make the type the same as the left
1250 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001251 setType(mLeft->getType());
1252
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001253 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001254 // Binary operations results in temporary variables unless both
1255 // operands are const.
1256 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1257 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001258 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001259 getTypePointer()->setQualifier(EvqTemporary);
1260 }
1261
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001262 // Handle indexing ops.
1263 switch (mOp)
1264 {
1265 case EOpIndexDirect:
1266 case EOpIndexIndirect:
1267 if (mLeft->isArray())
1268 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001269 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001270 }
1271 else if (mLeft->isMatrix())
1272 {
1273 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1274 static_cast<unsigned char>(mLeft->getRows())));
1275 }
1276 else if (mLeft->isVector())
1277 {
1278 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1279 }
1280 else
1281 {
1282 UNREACHABLE();
1283 }
1284 return;
1285 case EOpIndexDirectStruct:
1286 {
1287 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1288 const int i = mRight->getAsConstantUnion()->getIConst(0);
1289 setType(*fields[i]->type());
1290 getTypePointer()->setQualifier(resultQualifier);
1291 return;
1292 }
1293 case EOpIndexDirectInterfaceBlock:
1294 {
1295 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1296 const int i = mRight->getAsConstantUnion()->getIConst(0);
1297 setType(*fields[i]->type());
1298 getTypePointer()->setQualifier(resultQualifier);
1299 return;
1300 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001301 default:
1302 break;
1303 }
1304
1305 ASSERT(mLeft->isArray() == mRight->isArray());
1306
1307 // The result gets promoted to the highest precision.
1308 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1309 getTypePointer()->setPrecision(higherPrecision);
1310
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001311 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001312
1313 //
1314 // All scalars or structs. Code after this test assumes this case is removed!
1315 //
1316 if (nominalSize == 1)
1317 {
1318 switch (mOp)
1319 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001320 //
1321 // Promote to conditional
1322 //
1323 case EOpEqual:
1324 case EOpNotEqual:
1325 case EOpLessThan:
1326 case EOpGreaterThan:
1327 case EOpLessThanEqual:
1328 case EOpGreaterThanEqual:
1329 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1330 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001331
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001332 //
1333 // And and Or operate on conditionals
1334 //
1335 case EOpLogicalAnd:
1336 case EOpLogicalXor:
1337 case EOpLogicalOr:
1338 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1339 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1340 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001341
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001342 default:
1343 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001344 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001345 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001346 }
1347
1348 // If we reach here, at least one of the operands is vector or matrix.
1349 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001350 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001351
Jamie Madillb1a85f42014-08-19 15:23:24 -04001352 switch (mOp)
1353 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001354 case EOpMul:
1355 break;
1356 case EOpMatrixTimesScalar:
1357 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001358 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001359 setType(TType(basicType, higherPrecision, resultQualifier,
1360 static_cast<unsigned char>(mRight->getCols()),
1361 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001362 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001363 break;
1364 case EOpMatrixTimesVector:
1365 setType(TType(basicType, higherPrecision, resultQualifier,
1366 static_cast<unsigned char>(mLeft->getRows()), 1));
1367 break;
1368 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001369 setType(TType(basicType, higherPrecision, resultQualifier,
1370 static_cast<unsigned char>(mRight->getCols()),
1371 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001372 break;
1373 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001374 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001375 static_cast<unsigned char>(nominalSize), 1));
1376 break;
1377 case EOpVectorTimesMatrix:
1378 setType(TType(basicType, higherPrecision, resultQualifier,
1379 static_cast<unsigned char>(mRight->getCols()), 1));
1380 break;
1381 case EOpMulAssign:
1382 case EOpVectorTimesScalarAssign:
1383 case EOpVectorTimesMatrixAssign:
1384 case EOpMatrixTimesScalarAssign:
1385 case EOpMatrixTimesMatrixAssign:
1386 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1387 break;
1388 case EOpAssign:
1389 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001390 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1391 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1392 break;
1393 case EOpAdd:
1394 case EOpSub:
1395 case EOpDiv:
1396 case EOpIMod:
1397 case EOpBitShiftLeft:
1398 case EOpBitShiftRight:
1399 case EOpBitwiseAnd:
1400 case EOpBitwiseXor:
1401 case EOpBitwiseOr:
1402 case EOpAddAssign:
1403 case EOpSubAssign:
1404 case EOpDivAssign:
1405 case EOpIModAssign:
1406 case EOpBitShiftLeftAssign:
1407 case EOpBitShiftRightAssign:
1408 case EOpBitwiseAndAssign:
1409 case EOpBitwiseXorAssign:
1410 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001411 {
1412 const int secondarySize =
1413 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1414 setType(TType(basicType, higherPrecision, resultQualifier,
1415 static_cast<unsigned char>(nominalSize),
1416 static_cast<unsigned char>(secondarySize)));
1417 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001418 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001419 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001420 case EOpEqual:
1421 case EOpNotEqual:
1422 case EOpLessThan:
1423 case EOpGreaterThan:
1424 case EOpLessThanEqual:
1425 case EOpGreaterThanEqual:
1426 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1427 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001428 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001429 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001430
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001431 case EOpIndexDirect:
1432 case EOpIndexIndirect:
1433 case EOpIndexDirectInterfaceBlock:
1434 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001435 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001436 UNREACHABLE();
1437 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001438 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001439 UNREACHABLE();
1440 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001441 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001442}
1443
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001444bool TIntermConstantUnion::hasConstantValue() const
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001445{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001446 return true;
1447}
1448
1449const TConstantUnion *TIntermConstantUnion::getConstantValue() const
1450{
1451 return mUnionArrayPointer;
1452}
1453
1454const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
1455 const TConstantUnion *constArray,
1456 int index)
1457{
1458 if (type.isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001459 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001460 ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
1461 TType arrayElementType(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001462 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001463 size_t arrayElementSize = arrayElementType.getObjectSize();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001464 return &constArray[arrayElementSize * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001465 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001466 else if (type.isMatrix())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001467 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001468 ASSERT(index < type.getCols());
1469 int size = type.getRows();
1470 return &constArray[size * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001471 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001472 else if (type.isVector())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001473 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001474 ASSERT(index < type.getNominalSize());
1475 return &constArray[index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001476 }
1477 else
1478 {
1479 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001480 return nullptr;
1481 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001482}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001483
Olli Etuaho765924f2018-01-04 12:48:36 +02001484TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001485{
Olli Etuahob1de5a72018-03-28 14:07:57 +03001486 TIntermSwizzle *operandSwizzle = mOperand->getAsSwizzleNode();
1487 if (operandSwizzle)
1488 {
1489 // We need to fold the two swizzles into one, so that repeated swizzling can't cause stack
1490 // overflow in ParseContext::checkCanBeLValue().
1491 bool hadDuplicateOffsets = operandSwizzle->hasDuplicateOffsets();
1492 TVector<int> foldedOffsets;
1493 for (int offset : mSwizzleOffsets)
1494 {
1495 // Offset should already be validated.
1496 ASSERT(static_cast<size_t>(offset) < operandSwizzle->mSwizzleOffsets.size());
1497 foldedOffsets.push_back(operandSwizzle->mSwizzleOffsets[offset]);
1498 }
1499 operandSwizzle->mSwizzleOffsets = foldedOffsets;
1500 operandSwizzle->setType(getType());
1501 operandSwizzle->setHasFoldedDuplicateOffsets(hadDuplicateOffsets);
1502 return operandSwizzle;
1503 }
Olli Etuahob6fa0432016-09-28 16:28:05 +01001504 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1505 if (operandConstant == nullptr)
1506 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001507 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001508 }
1509
1510 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1511 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1512 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001513 constArray[i] = *TIntermConstantUnion::FoldIndexing(
1514 operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
Olli Etuahob6fa0432016-09-28 16:28:05 +01001515 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001516 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001517}
1518
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001519TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1520{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001521 const TConstantUnion *rightConstant = mRight->getConstantValue();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001522 switch (mOp)
1523 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001524 case EOpComma:
1525 {
1526 if (mLeft->hasSideEffects())
1527 {
1528 return this;
1529 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001530 return mRight;
1531 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001532 case EOpIndexDirect:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001533 case EOpIndexDirectStruct:
1534 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001535 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001536 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001537 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001538 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001539 size_t index = static_cast<size_t>(rightConstant->getIConst());
1540 TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
1541 if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
1542 !leftAggregate->hasSideEffects())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001543 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001544 ASSERT(index < leftAggregate->getSequence()->size());
1545 // This transformation can't add complexity as we're eliminating the constructor
1546 // entirely.
1547 return leftAggregate->getSequence()->at(index)->getAsTyped();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001548 }
1549
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001550 // If the indexed value is already a constant union, we can't increase duplication of
1551 // data by folding the indexing. Also fold the node in case it's generally beneficial to
1552 // replace this type of node with a constant union even if that would mean duplicating
1553 // data.
1554 if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
1555 {
1556 const TConstantUnion *constantValue = getConstantValue();
1557 if (constantValue == nullptr)
1558 {
1559 return this;
1560 }
1561 return CreateFoldedNode(constantValue, this);
1562 }
1563 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001564 }
1565 case EOpIndexIndirect:
1566 case EOpIndexDirectInterfaceBlock:
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001567 case EOpInitialize:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001568 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001569 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001570 default:
1571 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001572 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001573 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001574 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001575 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001576 const TConstantUnion *leftConstant = mLeft->getConstantValue();
1577 if (leftConstant == nullptr)
1578 {
1579 return this;
1580 }
1581 const TConstantUnion *constArray =
1582 TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
1583 mRight->getType(), diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001584 if (!constArray)
1585 {
1586 return this;
1587 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001588 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001589 }
1590 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001591}
1592
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001593bool TIntermBinary::hasConstantValue() const
1594{
1595 switch (mOp)
1596 {
1597 case EOpIndexDirect:
1598 case EOpIndexDirectStruct:
1599 {
1600 if (mLeft->hasConstantValue() && mRight->hasConstantValue())
1601 {
1602 return true;
1603 }
Nico Weber41b072b2018-02-09 10:01:32 -05001604 break;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001605 }
1606 default:
1607 break;
1608 }
1609 return false;
1610}
1611
1612const TConstantUnion *TIntermBinary::getConstantValue() const
1613{
1614 if (!hasConstantValue())
1615 {
1616 return nullptr;
1617 }
1618
1619 const TConstantUnion *leftConstantValue = mLeft->getConstantValue();
1620 int index = mRight->getConstantValue()->getIConst();
1621 const TConstantUnion *constIndexingResult = nullptr;
1622 if (mOp == EOpIndexDirect)
1623 {
1624 constIndexingResult =
1625 TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
1626 }
1627 else
1628 {
1629 ASSERT(mOp == EOpIndexDirectStruct);
1630 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1631
1632 size_t previousFieldsSize = 0;
1633 for (int i = 0; i < index; ++i)
1634 {
1635 previousFieldsSize += fields[i]->type()->getObjectSize();
1636 }
1637 constIndexingResult = leftConstantValue + previousFieldsSize;
1638 }
1639 return constIndexingResult;
1640}
1641
Olli Etuahof119a262016-08-19 15:54:22 +03001642TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001643{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301644 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001645
1646 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301647 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001648 // The size of runtime-sized arrays may only be determined at runtime.
1649 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001650 {
1651 return this;
1652 }
1653 constArray = new TConstantUnion[1];
1654 constArray->setIConst(mOperand->getOutermostArraySize());
1655 }
1656 else
1657 {
1658 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1659 if (operandConstant == nullptr)
1660 {
1661 return this;
1662 }
1663
1664 switch (mOp)
1665 {
1666 case EOpAny:
1667 case EOpAll:
1668 case EOpLength:
1669 case EOpTranspose:
1670 case EOpDeterminant:
1671 case EOpInverse:
1672 case EOpPackSnorm2x16:
1673 case EOpUnpackSnorm2x16:
1674 case EOpPackUnorm2x16:
1675 case EOpUnpackUnorm2x16:
1676 case EOpPackHalf2x16:
1677 case EOpUnpackHalf2x16:
1678 case EOpPackUnorm4x8:
1679 case EOpPackSnorm4x8:
1680 case EOpUnpackUnorm4x8:
1681 case EOpUnpackSnorm4x8:
1682 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1683 break;
1684 default:
1685 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1686 break;
1687 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301688 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001689 if (constArray == nullptr)
1690 {
1691 return this;
1692 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001693 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001694}
1695
Olli Etuahof119a262016-08-19 15:54:22 +03001696TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001697{
1698 // Make sure that all params are constant before actual constant folding.
1699 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001700 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001701 if (param->getAsConstantUnion() == nullptr)
1702 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001703 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001704 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001705 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001706 const TConstantUnion *constArray = nullptr;
Olli Etuaho1d122782015-11-06 15:35:17 +02001707 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001708 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001709 if (mType.canReplaceWithConstantUnion())
Olli Etuaho765924f2018-01-04 12:48:36 +02001710 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001711 constArray = getConstantValue();
Olli Etuaho765924f2018-01-04 12:48:36 +02001712 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001713 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001714 else if (CanFoldAggregateBuiltInOp(mOp))
Olli Etuaho2768bc82017-12-12 11:51:48 +02001715 {
Olli Etuahof119a262016-08-19 15:54:22 +03001716 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001717 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001718 if (constArray == nullptr)
1719 {
1720 return this;
1721 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001722 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001723}
1724
Jamie Madillb1a85f42014-08-19 15:23:24 -04001725//
1726// The fold functions see if an operation on a constant can be done in place,
1727// without generating run-time code.
1728//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001729// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001730//
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001731const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
1732 const TConstantUnion *leftArray,
1733 const TType &leftType,
1734 const TConstantUnion *rightArray,
1735 const TType &rightType,
1736 TDiagnostics *diagnostics,
1737 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001738{
Olli Etuahof119a262016-08-19 15:54:22 +03001739 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001740
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001741 size_t objectSize = leftType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001742
1743 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001744 if (rightType.getObjectSize() == 1 && objectSize > 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001745 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001746 rightArray = Vectorize(*rightArray, objectSize);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001747 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001748 else if (rightType.getObjectSize() > 1 && objectSize == 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001749 {
1750 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001751 leftArray = Vectorize(*leftArray, rightType.getObjectSize());
1752 objectSize = rightType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001753 }
1754
1755 TConstantUnion *resultArray = nullptr;
1756
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001757 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001758 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001759 case EOpAdd:
1760 resultArray = new TConstantUnion[objectSize];
1761 for (size_t i = 0; i < objectSize; i++)
1762 resultArray[i] =
1763 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1764 break;
1765 case EOpSub:
1766 resultArray = new TConstantUnion[objectSize];
1767 for (size_t i = 0; i < objectSize; i++)
1768 resultArray[i] =
1769 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1770 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001771
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001772 case EOpMul:
1773 case EOpVectorTimesScalar:
1774 case EOpMatrixTimesScalar:
1775 resultArray = new TConstantUnion[objectSize];
1776 for (size_t i = 0; i < objectSize; i++)
1777 resultArray[i] =
1778 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1779 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001780
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001781 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001782 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001783 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001784 ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001785
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001786 const int leftCols = leftType.getCols();
1787 const int leftRows = leftType.getRows();
1788 const int rightCols = rightType.getCols();
1789 const int rightRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001790 const int resultCols = rightCols;
1791 const int resultRows = leftRows;
1792
1793 resultArray = new TConstantUnion[resultCols * resultRows];
1794 for (int row = 0; row < resultRows; row++)
1795 {
1796 for (int column = 0; column < resultCols; column++)
1797 {
1798 resultArray[resultRows * column + row].setFConst(0.0f);
1799 for (int i = 0; i < leftCols; i++)
1800 {
1801 resultArray[resultRows * column + row].setFConst(
1802 resultArray[resultRows * column + row].getFConst() +
1803 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001804 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001805 }
1806 }
1807 }
1808 }
1809 break;
1810
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001811 case EOpDiv:
1812 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001813 {
1814 resultArray = new TConstantUnion[objectSize];
1815 for (size_t i = 0; i < objectSize; i++)
1816 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001817 switch (leftType.getBasicType())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001818 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001819 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001820 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001821 ASSERT(op == EOpDiv);
1822 float dividend = leftArray[i].getFConst();
1823 float divisor = rightArray[i].getFConst();
1824 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001825 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001826 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001827 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001828 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001829 line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001830 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001831 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001832 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001833 }
1834 else
1835 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001836 diagnostics->warning(line, "Divide by zero during constant folding",
1837 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001838 bool negativeResult =
1839 std::signbit(dividend) != std::signbit(divisor);
1840 resultArray[i].setFConst(
1841 negativeResult ? -std::numeric_limits<float>::infinity()
1842 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001843 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001844 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001845 else if (gl::isInf(dividend) && gl::isInf(divisor))
1846 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001847 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001848 "Infinity divided by infinity during constant "
1849 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001850 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001851 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1852 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001853 else
1854 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001855 float result = dividend / divisor;
1856 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001857 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001858 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001859 line, "Constant folded division overflowed to infinity", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001860 }
1861 resultArray[i].setFConst(result);
1862 }
1863 break;
1864 }
1865 case EbtInt:
1866 if (rightArray[i] == 0)
1867 {
1868 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001869 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001870 resultArray[i].setIConst(INT_MAX);
1871 }
1872 else
1873 {
1874 int lhs = leftArray[i].getIConst();
1875 int divisor = rightArray[i].getIConst();
1876 if (op == EOpDiv)
1877 {
1878 // Check for the special case where the minimum representable number
1879 // is
1880 // divided by -1. If left alone this leads to integer overflow in
1881 // C++.
1882 // ESSL 3.00.6 section 4.1.3 Integers:
1883 // "However, for the case where the minimum representable value is
1884 // divided by -1, it is allowed to return either the minimum
1885 // representable value or the maximum representable value."
1886 if (lhs == -0x7fffffff - 1 && divisor == -1)
1887 {
1888 resultArray[i].setIConst(0x7fffffff);
1889 }
1890 else
1891 {
1892 resultArray[i].setIConst(lhs / divisor);
1893 }
Olli Etuahod4453572016-09-27 13:21:46 +01001894 }
1895 else
1896 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001897 ASSERT(op == EOpIMod);
1898 if (lhs < 0 || divisor < 0)
1899 {
1900 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1901 // when
1902 // either one of the operands is negative.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001903 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001904 "Negative modulus operator operand "
1905 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001906 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001907 resultArray[i].setIConst(0);
1908 }
1909 else
1910 {
1911 resultArray[i].setIConst(lhs % divisor);
1912 }
Olli Etuahod4453572016-09-27 13:21:46 +01001913 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001914 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001915 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001916
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001917 case EbtUInt:
1918 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001919 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001920 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001921 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001922 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001923 }
1924 else
1925 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001926 if (op == EOpDiv)
1927 {
1928 resultArray[i].setUConst(leftArray[i].getUConst() /
1929 rightArray[i].getUConst());
1930 }
1931 else
1932 {
1933 ASSERT(op == EOpIMod);
1934 resultArray[i].setUConst(leftArray[i].getUConst() %
1935 rightArray[i].getUConst());
1936 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001937 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001938 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001939
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001940 default:
1941 UNREACHABLE();
1942 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001943 }
1944 }
1945 }
1946 break;
1947
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001948 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001949 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001950 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001951 ASSERT(rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001952
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001953 const int matrixCols = leftType.getCols();
1954 const int matrixRows = leftType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001955
1956 resultArray = new TConstantUnion[matrixRows];
1957
1958 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1959 {
1960 resultArray[matrixRow].setFConst(0.0f);
1961 for (int col = 0; col < matrixCols; col++)
1962 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001963 resultArray[matrixRow].setFConst(
1964 resultArray[matrixRow].getFConst() +
1965 leftArray[col * matrixRows + matrixRow].getFConst() *
1966 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001967 }
1968 }
1969 }
1970 break;
1971
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001972 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001973 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001974 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001975 ASSERT(leftType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001976
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001977 const int matrixCols = rightType.getCols();
1978 const int matrixRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001979
1980 resultArray = new TConstantUnion[matrixCols];
1981
1982 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1983 {
1984 resultArray[matrixCol].setFConst(0.0f);
1985 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1986 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001987 resultArray[matrixCol].setFConst(
1988 resultArray[matrixCol].getFConst() +
1989 leftArray[matrixRow].getFConst() *
1990 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001991 }
1992 }
1993 }
1994 break;
1995
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001996 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001997 {
1998 resultArray = new TConstantUnion[objectSize];
1999 for (size_t i = 0; i < objectSize; i++)
2000 {
2001 resultArray[i] = leftArray[i] && rightArray[i];
2002 }
2003 }
2004 break;
2005
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002006 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002007 {
2008 resultArray = new TConstantUnion[objectSize];
2009 for (size_t i = 0; i < objectSize; i++)
2010 {
2011 resultArray[i] = leftArray[i] || rightArray[i];
2012 }
2013 }
2014 break;
2015
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002016 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002017 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002018 ASSERT(leftType.getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002019 resultArray = new TConstantUnion[objectSize];
2020 for (size_t i = 0; i < objectSize; i++)
2021 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03002022 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002023 }
2024 }
2025 break;
2026
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002027 case EOpBitwiseAnd:
2028 resultArray = new TConstantUnion[objectSize];
2029 for (size_t i = 0; i < objectSize; i++)
2030 resultArray[i] = leftArray[i] & rightArray[i];
2031 break;
2032 case EOpBitwiseXor:
2033 resultArray = new TConstantUnion[objectSize];
2034 for (size_t i = 0; i < objectSize; i++)
2035 resultArray[i] = leftArray[i] ^ rightArray[i];
2036 break;
2037 case EOpBitwiseOr:
2038 resultArray = new TConstantUnion[objectSize];
2039 for (size_t i = 0; i < objectSize; i++)
2040 resultArray[i] = leftArray[i] | rightArray[i];
2041 break;
2042 case EOpBitShiftLeft:
2043 resultArray = new TConstantUnion[objectSize];
2044 for (size_t i = 0; i < objectSize; i++)
2045 resultArray[i] =
2046 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
2047 break;
2048 case EOpBitShiftRight:
2049 resultArray = new TConstantUnion[objectSize];
2050 for (size_t i = 0; i < objectSize; i++)
2051 resultArray[i] =
2052 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
2053 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002054
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002055 case EOpLessThan:
2056 ASSERT(objectSize == 1);
2057 resultArray = new TConstantUnion[1];
2058 resultArray->setBConst(*leftArray < *rightArray);
2059 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002060
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002061 case EOpGreaterThan:
2062 ASSERT(objectSize == 1);
2063 resultArray = new TConstantUnion[1];
2064 resultArray->setBConst(*leftArray > *rightArray);
2065 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002066
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002067 case EOpLessThanEqual:
2068 ASSERT(objectSize == 1);
2069 resultArray = new TConstantUnion[1];
2070 resultArray->setBConst(!(*leftArray > *rightArray));
2071 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002072
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002073 case EOpGreaterThanEqual:
2074 ASSERT(objectSize == 1);
2075 resultArray = new TConstantUnion[1];
2076 resultArray->setBConst(!(*leftArray < *rightArray));
2077 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002078
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002079 case EOpEqual:
2080 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002081 {
2082 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002083 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002084 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002085 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002086 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002087 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002088 equal = false;
2089 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002090 }
2091 }
2092 if (op == EOpEqual)
2093 {
2094 resultArray->setBConst(equal);
2095 }
2096 else
2097 {
2098 resultArray->setBConst(!equal);
2099 }
2100 }
2101 break;
2102
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002103 default:
2104 UNREACHABLE();
2105 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002106 }
2107 return resultArray;
2108}
2109
Olli Etuahof119a262016-08-19 15:54:22 +03002110// The fold functions do operations on a constant at GLSL compile time, without generating run-time
2111// code. Returns the constant value to keep using. Nullptr should not be returned.
2112TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04002113{
Olli Etuahof119a262016-08-19 15:54:22 +03002114 // Do operations where the return type may have a different number of components compared to the
2115 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04002116
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002117 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002118 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302119
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002120 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302121 TConstantUnion *resultArray = nullptr;
2122 switch (op)
2123 {
Olli Etuahof119a262016-08-19 15:54:22 +03002124 case EOpAny:
2125 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302126 resultArray = new TConstantUnion();
2127 resultArray->setBConst(false);
2128 for (size_t i = 0; i < objectSize; i++)
2129 {
2130 if (operandArray[i].getBConst())
2131 {
2132 resultArray->setBConst(true);
2133 break;
2134 }
2135 }
2136 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302137
Olli Etuahof119a262016-08-19 15:54:22 +03002138 case EOpAll:
2139 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302140 resultArray = new TConstantUnion();
2141 resultArray->setBConst(true);
2142 for (size_t i = 0; i < objectSize; i++)
2143 {
2144 if (!operandArray[i].getBConst())
2145 {
2146 resultArray->setBConst(false);
2147 break;
2148 }
2149 }
2150 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302151
Olli Etuahof119a262016-08-19 15:54:22 +03002152 case EOpLength:
2153 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302154 resultArray = new TConstantUnion();
2155 resultArray->setFConst(VectorLength(operandArray, objectSize));
2156 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302157
Olli Etuahof119a262016-08-19 15:54:22 +03002158 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302159 {
Olli Etuahof119a262016-08-19 15:54:22 +03002160 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302161 resultArray = new TConstantUnion[objectSize];
2162 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002163 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302164 SetUnionArrayFromMatrix(result, resultArray);
2165 break;
2166 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302167
Olli Etuahof119a262016-08-19 15:54:22 +03002168 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302169 {
Olli Etuahof119a262016-08-19 15:54:22 +03002170 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302171 unsigned int size = getType().getNominalSize();
2172 ASSERT(size >= 2 && size <= 4);
2173 resultArray = new TConstantUnion();
2174 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
2175 break;
2176 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302177
Olli Etuahof119a262016-08-19 15:54:22 +03002178 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302179 {
Olli Etuahof119a262016-08-19 15:54:22 +03002180 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302181 unsigned int size = getType().getNominalSize();
2182 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03002183 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05302184 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
2185 SetUnionArrayFromMatrix(result, resultArray);
2186 break;
2187 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302188
Olli Etuahof119a262016-08-19 15:54:22 +03002189 case EOpPackSnorm2x16:
2190 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302191 ASSERT(getType().getNominalSize() == 2);
2192 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002193 resultArray->setUConst(
2194 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302195 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302196
Olli Etuahof119a262016-08-19 15:54:22 +03002197 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302198 {
Olli Etuahof119a262016-08-19 15:54:22 +03002199 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302200 resultArray = new TConstantUnion[2];
2201 float f1, f2;
2202 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2203 resultArray[0].setFConst(f1);
2204 resultArray[1].setFConst(f2);
2205 break;
2206 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302207
Olli Etuahof119a262016-08-19 15:54:22 +03002208 case EOpPackUnorm2x16:
2209 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302210 ASSERT(getType().getNominalSize() == 2);
2211 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002212 resultArray->setUConst(
2213 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302214 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302215
Olli Etuahof119a262016-08-19 15:54:22 +03002216 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302217 {
Olli Etuahof119a262016-08-19 15:54:22 +03002218 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302219 resultArray = new TConstantUnion[2];
2220 float f1, f2;
2221 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2222 resultArray[0].setFConst(f1);
2223 resultArray[1].setFConst(f2);
2224 break;
2225 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302226
Olli Etuahof119a262016-08-19 15:54:22 +03002227 case EOpPackHalf2x16:
2228 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302229 ASSERT(getType().getNominalSize() == 2);
2230 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002231 resultArray->setUConst(
2232 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302233 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302234
Olli Etuahof119a262016-08-19 15:54:22 +03002235 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302236 {
Olli Etuahof119a262016-08-19 15:54:22 +03002237 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302238 resultArray = new TConstantUnion[2];
2239 float f1, f2;
2240 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2241 resultArray[0].setFConst(f1);
2242 resultArray[1].setFConst(f2);
2243 break;
2244 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302245
Olli Etuaho25aef452017-01-29 16:15:44 -08002246 case EOpPackUnorm4x8:
2247 {
2248 ASSERT(getType().getBasicType() == EbtFloat);
2249 resultArray = new TConstantUnion();
2250 resultArray->setUConst(
2251 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2252 operandArray[2].getFConst(), operandArray[3].getFConst()));
2253 break;
2254 }
2255 case EOpPackSnorm4x8:
2256 {
2257 ASSERT(getType().getBasicType() == EbtFloat);
2258 resultArray = new TConstantUnion();
2259 resultArray->setUConst(
2260 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2261 operandArray[2].getFConst(), operandArray[3].getFConst()));
2262 break;
2263 }
2264 case EOpUnpackUnorm4x8:
2265 {
2266 ASSERT(getType().getBasicType() == EbtUInt);
2267 resultArray = new TConstantUnion[4];
2268 float f[4];
2269 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2270 for (size_t i = 0; i < 4; ++i)
2271 {
2272 resultArray[i].setFConst(f[i]);
2273 }
2274 break;
2275 }
2276 case EOpUnpackSnorm4x8:
2277 {
2278 ASSERT(getType().getBasicType() == EbtUInt);
2279 resultArray = new TConstantUnion[4];
2280 float f[4];
2281 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2282 for (size_t i = 0; i < 4; ++i)
2283 {
2284 resultArray[i].setFConst(f[i]);
2285 }
2286 break;
2287 }
2288
Olli Etuahof119a262016-08-19 15:54:22 +03002289 default:
2290 UNREACHABLE();
2291 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302292 }
2293
2294 return resultArray;
2295}
2296
Olli Etuahof119a262016-08-19 15:54:22 +03002297TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2298 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302299{
Olli Etuahof119a262016-08-19 15:54:22 +03002300 // Do unary operations where each component of the result is computed based on the corresponding
2301 // component of the operand. Also folds normalize, though the divisor in that case takes all
2302 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302303
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002304 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002305 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002306
2307 size_t objectSize = getType().getObjectSize();
2308
Arun Patoleab2b9a22015-07-06 18:27:56 +05302309 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2310 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302311 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002312 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302313 {
Olli Etuahof119a262016-08-19 15:54:22 +03002314 case EOpNegative:
2315 switch (getType().getBasicType())
2316 {
2317 case EbtFloat:
2318 resultArray[i].setFConst(-operandArray[i].getFConst());
2319 break;
2320 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002321 if (operandArray[i] == std::numeric_limits<int>::min())
2322 {
2323 // The minimum representable integer doesn't have a positive
2324 // counterpart, rather the negation overflows and in ESSL is supposed to
2325 // wrap back to the minimum representable integer. Make sure that we
2326 // don't actually let the negation overflow, which has undefined
2327 // behavior in C++.
2328 resultArray[i].setIConst(std::numeric_limits<int>::min());
2329 }
2330 else
2331 {
2332 resultArray[i].setIConst(-operandArray[i].getIConst());
2333 }
Olli Etuahof119a262016-08-19 15:54:22 +03002334 break;
2335 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002336 if (operandArray[i] == 0x80000000u)
2337 {
2338 resultArray[i].setUConst(0x80000000u);
2339 }
2340 else
2341 {
2342 resultArray[i].setUConst(static_cast<unsigned int>(
2343 -static_cast<int>(operandArray[i].getUConst())));
2344 }
Olli Etuahof119a262016-08-19 15:54:22 +03002345 break;
2346 default:
2347 UNREACHABLE();
2348 return nullptr;
2349 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302350 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302351
Olli Etuahof119a262016-08-19 15:54:22 +03002352 case EOpPositive:
2353 switch (getType().getBasicType())
2354 {
2355 case EbtFloat:
2356 resultArray[i].setFConst(operandArray[i].getFConst());
2357 break;
2358 case EbtInt:
2359 resultArray[i].setIConst(operandArray[i].getIConst());
2360 break;
2361 case EbtUInt:
2362 resultArray[i].setUConst(static_cast<unsigned int>(
2363 static_cast<int>(operandArray[i].getUConst())));
2364 break;
2365 default:
2366 UNREACHABLE();
2367 return nullptr;
2368 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302369 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302370
Olli Etuahof119a262016-08-19 15:54:22 +03002371 case EOpLogicalNot:
2372 switch (getType().getBasicType())
2373 {
2374 case EbtBool:
2375 resultArray[i].setBConst(!operandArray[i].getBConst());
2376 break;
2377 default:
2378 UNREACHABLE();
2379 return nullptr;
2380 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302381 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302382
Olli Etuahof119a262016-08-19 15:54:22 +03002383 case EOpBitwiseNot:
2384 switch (getType().getBasicType())
2385 {
2386 case EbtInt:
2387 resultArray[i].setIConst(~operandArray[i].getIConst());
2388 break;
2389 case EbtUInt:
2390 resultArray[i].setUConst(~operandArray[i].getUConst());
2391 break;
2392 default:
2393 UNREACHABLE();
2394 return nullptr;
2395 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302396 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302397
Olli Etuahof119a262016-08-19 15:54:22 +03002398 case EOpRadians:
2399 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302400 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2401 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302402
Olli Etuahof119a262016-08-19 15:54:22 +03002403 case EOpDegrees:
2404 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302405 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2406 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302407
Olli Etuahof119a262016-08-19 15:54:22 +03002408 case EOpSin:
2409 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302410 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302411
Olli Etuahof119a262016-08-19 15:54:22 +03002412 case EOpCos:
2413 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2414 break;
2415
2416 case EOpTan:
2417 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2418 break;
2419
2420 case EOpAsin:
2421 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2422 // 0.
2423 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2424 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2425 diagnostics, &resultArray[i]);
2426 else
2427 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2428 break;
2429
2430 case EOpAcos:
2431 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2432 // 0.
2433 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2434 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2435 diagnostics, &resultArray[i]);
2436 else
2437 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2438 break;
2439
2440 case EOpAtan:
2441 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2442 break;
2443
2444 case EOpSinh:
2445 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2446 break;
2447
2448 case EOpCosh:
2449 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2450 break;
2451
2452 case EOpTanh:
2453 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2454 break;
2455
2456 case EOpAsinh:
2457 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2458 break;
2459
2460 case EOpAcosh:
2461 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2462 if (operandArray[i].getFConst() < 1.0f)
2463 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2464 diagnostics, &resultArray[i]);
2465 else
2466 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2467 break;
2468
2469 case EOpAtanh:
2470 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2471 // 0.
2472 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2473 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2474 diagnostics, &resultArray[i]);
2475 else
2476 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2477 break;
2478
2479 case EOpAbs:
2480 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302481 {
Olli Etuahof119a262016-08-19 15:54:22 +03002482 case EbtFloat:
2483 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2484 break;
2485 case EbtInt:
2486 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2487 break;
2488 default:
2489 UNREACHABLE();
2490 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302491 }
2492 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002493
2494 case EOpSign:
2495 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302496 {
Olli Etuahof119a262016-08-19 15:54:22 +03002497 case EbtFloat:
2498 {
2499 float fConst = operandArray[i].getFConst();
2500 float fResult = 0.0f;
2501 if (fConst > 0.0f)
2502 fResult = 1.0f;
2503 else if (fConst < 0.0f)
2504 fResult = -1.0f;
2505 resultArray[i].setFConst(fResult);
2506 break;
2507 }
2508 case EbtInt:
2509 {
2510 int iConst = operandArray[i].getIConst();
2511 int iResult = 0;
2512 if (iConst > 0)
2513 iResult = 1;
2514 else if (iConst < 0)
2515 iResult = -1;
2516 resultArray[i].setIConst(iResult);
2517 break;
2518 }
2519 default:
2520 UNREACHABLE();
2521 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302522 }
2523 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302524
Olli Etuahof119a262016-08-19 15:54:22 +03002525 case EOpFloor:
2526 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2527 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302528
Olli Etuahof119a262016-08-19 15:54:22 +03002529 case EOpTrunc:
2530 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2531 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302532
Olli Etuahof119a262016-08-19 15:54:22 +03002533 case EOpRound:
2534 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2535 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302536
Olli Etuahof119a262016-08-19 15:54:22 +03002537 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302538 {
Olli Etuahof119a262016-08-19 15:54:22 +03002539 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302540 float x = operandArray[i].getFConst();
2541 float result;
2542 float fractPart = modff(x, &result);
2543 if (fabsf(fractPart) == 0.5f)
2544 result = 2.0f * roundf(x / 2.0f);
2545 else
2546 result = roundf(x);
2547 resultArray[i].setFConst(result);
2548 break;
2549 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302550
Olli Etuahof119a262016-08-19 15:54:22 +03002551 case EOpCeil:
2552 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2553 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302554
Olli Etuahof119a262016-08-19 15:54:22 +03002555 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302556 {
Olli Etuahof119a262016-08-19 15:54:22 +03002557 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302558 float x = operandArray[i].getFConst();
2559 resultArray[i].setFConst(x - floorf(x));
2560 break;
2561 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302562
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002563 case EOpIsnan:
Olli Etuahof119a262016-08-19 15:54:22 +03002564 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302565 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2566 break;
Arun Patole551279e2015-07-07 18:18:23 +05302567
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002568 case EOpIsinf:
Olli Etuahof119a262016-08-19 15:54:22 +03002569 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302570 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2571 break;
Arun Patole551279e2015-07-07 18:18:23 +05302572
Olli Etuahof119a262016-08-19 15:54:22 +03002573 case EOpFloatBitsToInt:
2574 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302575 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2576 break;
Arun Patole551279e2015-07-07 18:18:23 +05302577
Olli Etuahof119a262016-08-19 15:54:22 +03002578 case EOpFloatBitsToUint:
2579 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302580 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2581 break;
Arun Patole551279e2015-07-07 18:18:23 +05302582
Olli Etuahof119a262016-08-19 15:54:22 +03002583 case EOpIntBitsToFloat:
2584 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302585 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2586 break;
Arun Patole551279e2015-07-07 18:18:23 +05302587
Olli Etuahof119a262016-08-19 15:54:22 +03002588 case EOpUintBitsToFloat:
2589 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302590 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2591 break;
Arun Patole551279e2015-07-07 18:18:23 +05302592
Olli Etuahof119a262016-08-19 15:54:22 +03002593 case EOpExp:
2594 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2595 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302596
Olli Etuahof119a262016-08-19 15:54:22 +03002597 case EOpLog:
2598 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2599 if (operandArray[i].getFConst() <= 0.0f)
2600 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2601 diagnostics, &resultArray[i]);
2602 else
2603 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2604 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302605
Olli Etuahof119a262016-08-19 15:54:22 +03002606 case EOpExp2:
2607 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2608 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302609
Olli Etuahof119a262016-08-19 15:54:22 +03002610 case EOpLog2:
2611 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2612 // And log2f is not available on some plarforms like old android, so just using
2613 // log(x)/log(2) here.
2614 if (operandArray[i].getFConst() <= 0.0f)
2615 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2616 diagnostics, &resultArray[i]);
2617 else
2618 {
2619 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2620 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2621 }
2622 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302623
Olli Etuahof119a262016-08-19 15:54:22 +03002624 case EOpSqrt:
2625 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2626 if (operandArray[i].getFConst() < 0.0f)
2627 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2628 diagnostics, &resultArray[i]);
2629 else
2630 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2631 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302632
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002633 case EOpInversesqrt:
Olli Etuahof119a262016-08-19 15:54:22 +03002634 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2635 // so getting the square root first using builtin function sqrt() and then taking
2636 // its inverse.
2637 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2638 // result to 0.
2639 if (operandArray[i].getFConst() <= 0.0f)
2640 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2641 diagnostics, &resultArray[i]);
2642 else
2643 {
2644 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2645 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2646 }
2647 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302648
Olli Etuahod68924e2017-01-02 17:34:40 +00002649 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002650 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302651 resultArray[i].setBConst(!operandArray[i].getBConst());
2652 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302653
Olli Etuahof119a262016-08-19 15:54:22 +03002654 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302655 {
Olli Etuahof119a262016-08-19 15:54:22 +03002656 ASSERT(getType().getBasicType() == EbtFloat);
2657 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302658 float length = VectorLength(operandArray, objectSize);
2659 if (length)
2660 resultArray[i].setFConst(x / length);
2661 else
Olli Etuahof119a262016-08-19 15:54:22 +03002662 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2663 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302664 break;
2665 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002666 case EOpBitfieldReverse:
2667 {
2668 uint32_t value;
2669 if (getType().getBasicType() == EbtInt)
2670 {
2671 value = static_cast<uint32_t>(operandArray[i].getIConst());
2672 }
2673 else
2674 {
2675 ASSERT(getType().getBasicType() == EbtUInt);
2676 value = operandArray[i].getUConst();
2677 }
2678 uint32_t result = gl::BitfieldReverse(value);
2679 if (getType().getBasicType() == EbtInt)
2680 {
2681 resultArray[i].setIConst(static_cast<int32_t>(result));
2682 }
2683 else
2684 {
2685 resultArray[i].setUConst(result);
2686 }
2687 break;
2688 }
2689 case EOpBitCount:
2690 {
2691 uint32_t value;
2692 if (getType().getBasicType() == EbtInt)
2693 {
2694 value = static_cast<uint32_t>(operandArray[i].getIConst());
2695 }
2696 else
2697 {
2698 ASSERT(getType().getBasicType() == EbtUInt);
2699 value = operandArray[i].getUConst();
2700 }
2701 int result = gl::BitCount(value);
2702 resultArray[i].setIConst(result);
2703 break;
2704 }
2705 case EOpFindLSB:
2706 {
2707 uint32_t value;
2708 if (getType().getBasicType() == EbtInt)
2709 {
2710 value = static_cast<uint32_t>(operandArray[i].getIConst());
2711 }
2712 else
2713 {
2714 ASSERT(getType().getBasicType() == EbtUInt);
2715 value = operandArray[i].getUConst();
2716 }
2717 resultArray[i].setIConst(gl::FindLSB(value));
2718 break;
2719 }
2720 case EOpFindMSB:
2721 {
2722 uint32_t value;
2723 if (getType().getBasicType() == EbtInt)
2724 {
2725 int intValue = operandArray[i].getIConst();
2726 value = static_cast<uint32_t>(intValue);
2727 if (intValue < 0)
2728 {
2729 // Look for zero instead of one in value. This also handles the intValue ==
2730 // -1 special case, where the return value needs to be -1.
2731 value = ~value;
2732 }
2733 }
2734 else
2735 {
2736 ASSERT(getType().getBasicType() == EbtUInt);
2737 value = operandArray[i].getUConst();
2738 }
2739 resultArray[i].setIConst(gl::FindMSB(value));
2740 break;
2741 }
Olli Etuahof119a262016-08-19 15:54:22 +03002742 case EOpDFdx:
2743 case EOpDFdy:
2744 case EOpFwidth:
2745 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302746 // Derivatives of constant arguments should be 0.
2747 resultArray[i].setFConst(0.0f);
2748 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302749
Olli Etuahof119a262016-08-19 15:54:22 +03002750 default:
2751 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302752 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302753 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002754
Arun Patoleab2b9a22015-07-06 18:27:56 +05302755 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002756}
2757
Olli Etuahof119a262016-08-19 15:54:22 +03002758void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2759 FloatTypeUnaryFunc builtinFunc,
2760 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302761{
2762 ASSERT(builtinFunc);
2763
Olli Etuahof119a262016-08-19 15:54:22 +03002764 ASSERT(getType().getBasicType() == EbtFloat);
2765 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302766}
2767
Jamie Madillb1a85f42014-08-19 15:23:24 -04002768// static
Olli Etuahof119a262016-08-19 15:54:22 +03002769TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2770 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302771{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002772 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002773 TIntermSequence *arguments = aggregate->getSequence();
2774 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2775 std::vector<const TConstantUnion *> unionArrays(argsCount);
2776 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002777 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302778 TBasicType basicType = EbtVoid;
2779 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002780 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302781 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002782 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2783 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302784
2785 if (i == 0)
2786 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002787 basicType = argConstant->getType().getBasicType();
2788 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302789 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002790 unionArrays[i] = argConstant->getConstantValue();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002791 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002792 if (objectSizes[i] > maxObjectSize)
2793 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302794 }
2795
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002796 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302797 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002798 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302799 if (objectSizes[i] != maxObjectSize)
2800 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2801 }
Arun Patole274f0702015-05-05 13:33:30 +05302802
Olli Etuahob43846e2015-06-02 18:18:57 +03002803 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002804
2805 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302806 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002807 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302808 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002809 ASSERT(basicType == EbtFloat);
2810 resultArray = new TConstantUnion[maxObjectSize];
2811 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302812 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002813 float y = unionArrays[0][i].getFConst();
2814 float x = unionArrays[1][i].getFConst();
2815 // Results are undefined if x and y are both 0.
2816 if (x == 0.0f && y == 0.0f)
2817 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2818 else
2819 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302820 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002821 break;
2822 }
Arun Patolebf790422015-05-18 17:53:04 +05302823
Olli Etuaho51182ab2017-01-22 00:12:29 +00002824 case EOpPow:
2825 {
2826 ASSERT(basicType == EbtFloat);
2827 resultArray = new TConstantUnion[maxObjectSize];
2828 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302829 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002830 float x = unionArrays[0][i].getFConst();
2831 float y = unionArrays[1][i].getFConst();
2832 // Results are undefined if x < 0.
2833 // Results are undefined if x = 0 and y <= 0.
2834 if (x < 0.0f)
2835 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2836 else if (x == 0.0f && y <= 0.0f)
2837 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2838 else
2839 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302840 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002841 break;
2842 }
Arun Patolebf790422015-05-18 17:53:04 +05302843
Olli Etuaho51182ab2017-01-22 00:12:29 +00002844 case EOpMod:
2845 {
2846 ASSERT(basicType == EbtFloat);
2847 resultArray = new TConstantUnion[maxObjectSize];
2848 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302849 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002850 float x = unionArrays[0][i].getFConst();
2851 float y = unionArrays[1][i].getFConst();
2852 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302853 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002854 break;
2855 }
Arun Patolebf790422015-05-18 17:53:04 +05302856
Olli Etuaho51182ab2017-01-22 00:12:29 +00002857 case EOpMin:
2858 {
2859 resultArray = new TConstantUnion[maxObjectSize];
2860 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302861 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002862 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302863 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002864 case EbtFloat:
2865 resultArray[i].setFConst(
2866 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2867 break;
2868 case EbtInt:
2869 resultArray[i].setIConst(
2870 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2871 break;
2872 case EbtUInt:
2873 resultArray[i].setUConst(
2874 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2875 break;
2876 default:
2877 UNREACHABLE();
2878 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302879 }
2880 }
2881 break;
Arun Patole274f0702015-05-05 13:33:30 +05302882 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002883
2884 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302885 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002886 resultArray = new TConstantUnion[maxObjectSize];
2887 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302888 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002889 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302890 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002891 case EbtFloat:
2892 resultArray[i].setFConst(
2893 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2894 break;
2895 case EbtInt:
2896 resultArray[i].setIConst(
2897 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2898 break;
2899 case EbtUInt:
2900 resultArray[i].setUConst(
2901 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2902 break;
2903 default:
2904 UNREACHABLE();
2905 break;
Arun Patole274f0702015-05-05 13:33:30 +05302906 }
2907 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002908 break;
Arun Patole274f0702015-05-05 13:33:30 +05302909 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002910
2911 case EOpStep:
2912 {
2913 ASSERT(basicType == EbtFloat);
2914 resultArray = new TConstantUnion[maxObjectSize];
2915 for (size_t i = 0; i < maxObjectSize; i++)
2916 resultArray[i].setFConst(
2917 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2918 break;
2919 }
2920
2921 case EOpLessThanComponentWise:
2922 {
2923 resultArray = new TConstantUnion[maxObjectSize];
2924 for (size_t i = 0; i < maxObjectSize; i++)
2925 {
2926 switch (basicType)
2927 {
2928 case EbtFloat:
2929 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2930 unionArrays[1][i].getFConst());
2931 break;
2932 case EbtInt:
2933 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2934 unionArrays[1][i].getIConst());
2935 break;
2936 case EbtUInt:
2937 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2938 unionArrays[1][i].getUConst());
2939 break;
2940 default:
2941 UNREACHABLE();
2942 break;
2943 }
2944 }
2945 break;
2946 }
2947
2948 case EOpLessThanEqualComponentWise:
2949 {
2950 resultArray = new TConstantUnion[maxObjectSize];
2951 for (size_t i = 0; i < maxObjectSize; i++)
2952 {
2953 switch (basicType)
2954 {
2955 case EbtFloat:
2956 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2957 unionArrays[1][i].getFConst());
2958 break;
2959 case EbtInt:
2960 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2961 unionArrays[1][i].getIConst());
2962 break;
2963 case EbtUInt:
2964 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2965 unionArrays[1][i].getUConst());
2966 break;
2967 default:
2968 UNREACHABLE();
2969 break;
2970 }
2971 }
2972 break;
2973 }
2974
2975 case EOpGreaterThanComponentWise:
2976 {
2977 resultArray = new TConstantUnion[maxObjectSize];
2978 for (size_t i = 0; i < maxObjectSize; i++)
2979 {
2980 switch (basicType)
2981 {
2982 case EbtFloat:
2983 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2984 unionArrays[1][i].getFConst());
2985 break;
2986 case EbtInt:
2987 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2988 unionArrays[1][i].getIConst());
2989 break;
2990 case EbtUInt:
2991 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2992 unionArrays[1][i].getUConst());
2993 break;
2994 default:
2995 UNREACHABLE();
2996 break;
2997 }
2998 }
2999 break;
3000 }
3001 case EOpGreaterThanEqualComponentWise:
3002 {
3003 resultArray = new TConstantUnion[maxObjectSize];
3004 for (size_t i = 0; i < maxObjectSize; i++)
3005 {
3006 switch (basicType)
3007 {
3008 case EbtFloat:
3009 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
3010 unionArrays[1][i].getFConst());
3011 break;
3012 case EbtInt:
3013 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
3014 unionArrays[1][i].getIConst());
3015 break;
3016 case EbtUInt:
3017 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
3018 unionArrays[1][i].getUConst());
3019 break;
3020 default:
3021 UNREACHABLE();
3022 break;
3023 }
3024 }
3025 }
3026 break;
3027
3028 case EOpEqualComponentWise:
3029 {
3030 resultArray = new TConstantUnion[maxObjectSize];
3031 for (size_t i = 0; i < maxObjectSize; i++)
3032 {
3033 switch (basicType)
3034 {
3035 case EbtFloat:
3036 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
3037 unionArrays[1][i].getFConst());
3038 break;
3039 case EbtInt:
3040 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
3041 unionArrays[1][i].getIConst());
3042 break;
3043 case EbtUInt:
3044 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
3045 unionArrays[1][i].getUConst());
3046 break;
3047 case EbtBool:
3048 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
3049 unionArrays[1][i].getBConst());
3050 break;
3051 default:
3052 UNREACHABLE();
3053 break;
3054 }
3055 }
3056 break;
3057 }
3058
3059 case EOpNotEqualComponentWise:
3060 {
3061 resultArray = new TConstantUnion[maxObjectSize];
3062 for (size_t i = 0; i < maxObjectSize; i++)
3063 {
3064 switch (basicType)
3065 {
3066 case EbtFloat:
3067 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
3068 unionArrays[1][i].getFConst());
3069 break;
3070 case EbtInt:
3071 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3072 unionArrays[1][i].getIConst());
3073 break;
3074 case EbtUInt:
3075 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3076 unionArrays[1][i].getUConst());
3077 break;
3078 case EbtBool:
3079 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3080 unionArrays[1][i].getBConst());
3081 break;
3082 default:
3083 UNREACHABLE();
3084 break;
3085 }
3086 }
3087 break;
3088 }
3089
3090 case EOpDistance:
3091 {
3092 ASSERT(basicType == EbtFloat);
3093 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3094 resultArray = new TConstantUnion();
3095 for (size_t i = 0; i < maxObjectSize; i++)
3096 {
3097 float x = unionArrays[0][i].getFConst();
3098 float y = unionArrays[1][i].getFConst();
3099 distanceArray[i].setFConst(x - y);
3100 }
3101 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3102 break;
3103 }
3104
3105 case EOpDot:
3106 ASSERT(basicType == EbtFloat);
3107 resultArray = new TConstantUnion();
3108 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3109 break;
3110
3111 case EOpCross:
3112 {
3113 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3114 resultArray = new TConstantUnion[maxObjectSize];
3115 float x0 = unionArrays[0][0].getFConst();
3116 float x1 = unionArrays[0][1].getFConst();
3117 float x2 = unionArrays[0][2].getFConst();
3118 float y0 = unionArrays[1][0].getFConst();
3119 float y1 = unionArrays[1][1].getFConst();
3120 float y2 = unionArrays[1][2].getFConst();
3121 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3122 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3123 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3124 break;
3125 }
3126
3127 case EOpReflect:
3128 {
3129 ASSERT(basicType == EbtFloat);
3130 // genType reflect (genType I, genType N) :
3131 // For the incident vector I and surface orientation N, returns the reflection
3132 // direction:
3133 // I - 2 * dot(N, I) * N.
3134 resultArray = new TConstantUnion[maxObjectSize];
3135 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3136 for (size_t i = 0; i < maxObjectSize; i++)
3137 {
3138 float result = unionArrays[0][i].getFConst() -
3139 2.0f * dotProduct * unionArrays[1][i].getFConst();
3140 resultArray[i].setFConst(result);
3141 }
3142 break;
3143 }
3144
3145 case EOpMulMatrixComponentWise:
3146 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003147 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3148 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003149 // Perform component-wise matrix multiplication.
3150 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003151 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003152 angle::Matrix<float> result =
3153 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3154 SetUnionArrayFromMatrix(result, resultArray);
3155 break;
3156 }
3157
3158 case EOpOuterProduct:
3159 {
3160 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003161 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3162 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003163 resultArray = new TConstantUnion[numRows * numCols];
3164 angle::Matrix<float> result =
3165 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3166 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3167 SetUnionArrayFromMatrix(result, resultArray);
3168 break;
3169 }
3170
3171 case EOpClamp:
3172 {
3173 resultArray = new TConstantUnion[maxObjectSize];
3174 for (size_t i = 0; i < maxObjectSize; i++)
3175 {
3176 switch (basicType)
3177 {
3178 case EbtFloat:
3179 {
3180 float x = unionArrays[0][i].getFConst();
3181 float min = unionArrays[1][i].getFConst();
3182 float max = unionArrays[2][i].getFConst();
3183 // Results are undefined if min > max.
3184 if (min > max)
3185 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3186 &resultArray[i]);
3187 else
3188 resultArray[i].setFConst(gl::clamp(x, min, max));
3189 break;
3190 }
3191
3192 case EbtInt:
3193 {
3194 int x = unionArrays[0][i].getIConst();
3195 int min = unionArrays[1][i].getIConst();
3196 int max = unionArrays[2][i].getIConst();
3197 // Results are undefined if min > max.
3198 if (min > max)
3199 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3200 &resultArray[i]);
3201 else
3202 resultArray[i].setIConst(gl::clamp(x, min, max));
3203 break;
3204 }
3205 case EbtUInt:
3206 {
3207 unsigned int x = unionArrays[0][i].getUConst();
3208 unsigned int min = unionArrays[1][i].getUConst();
3209 unsigned int max = unionArrays[2][i].getUConst();
3210 // Results are undefined if min > max.
3211 if (min > max)
3212 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3213 &resultArray[i]);
3214 else
3215 resultArray[i].setUConst(gl::clamp(x, min, max));
3216 break;
3217 }
3218 default:
3219 UNREACHABLE();
3220 break;
3221 }
3222 }
3223 break;
3224 }
3225
3226 case EOpMix:
3227 {
3228 ASSERT(basicType == EbtFloat);
3229 resultArray = new TConstantUnion[maxObjectSize];
3230 for (size_t i = 0; i < maxObjectSize; i++)
3231 {
3232 float x = unionArrays[0][i].getFConst();
3233 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003234 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003235 if (type == EbtFloat)
3236 {
3237 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3238 float a = unionArrays[2][i].getFConst();
3239 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3240 }
3241 else // 3rd parameter is EbtBool
3242 {
3243 ASSERT(type == EbtBool);
3244 // Selects which vector each returned component comes from.
3245 // For a component of a that is false, the corresponding component of x is
3246 // returned.
3247 // For a component of a that is true, the corresponding component of y is
3248 // returned.
3249 bool a = unionArrays[2][i].getBConst();
3250 resultArray[i].setFConst(a ? y : x);
3251 }
3252 }
3253 break;
3254 }
3255
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02003256 case EOpSmoothstep:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003257 {
3258 ASSERT(basicType == EbtFloat);
3259 resultArray = new TConstantUnion[maxObjectSize];
3260 for (size_t i = 0; i < maxObjectSize; i++)
3261 {
3262 float edge0 = unionArrays[0][i].getFConst();
3263 float edge1 = unionArrays[1][i].getFConst();
3264 float x = unionArrays[2][i].getFConst();
3265 // Results are undefined if edge0 >= edge1.
3266 if (edge0 >= edge1)
3267 {
3268 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3269 }
3270 else
3271 {
3272 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3273 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3274 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3275 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3276 }
3277 }
3278 break;
3279 }
3280
Olli Etuaho74da73f2017-02-01 15:37:48 +00003281 case EOpLdexp:
3282 {
3283 resultArray = new TConstantUnion[maxObjectSize];
3284 for (size_t i = 0; i < maxObjectSize; i++)
3285 {
3286 float x = unionArrays[0][i].getFConst();
3287 int exp = unionArrays[1][i].getIConst();
3288 if (exp > 128)
3289 {
3290 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3291 }
3292 else
3293 {
3294 resultArray[i].setFConst(gl::Ldexp(x, exp));
3295 }
3296 }
3297 break;
3298 }
3299
Jamie Madille72595b2017-06-06 15:12:26 -04003300 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003301 {
3302 ASSERT(basicType == EbtFloat);
3303 // genType faceforward(genType N, genType I, genType Nref) :
3304 // If dot(Nref, I) < 0 return N, otherwise return -N.
3305 resultArray = new TConstantUnion[maxObjectSize];
3306 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3307 for (size_t i = 0; i < maxObjectSize; i++)
3308 {
3309 if (dotProduct < 0)
3310 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3311 else
3312 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3313 }
3314 break;
3315 }
3316
3317 case EOpRefract:
3318 {
3319 ASSERT(basicType == EbtFloat);
3320 // genType refract(genType I, genType N, float eta) :
3321 // For the incident vector I and surface normal N, and the ratio of indices of
3322 // refraction eta,
3323 // return the refraction vector. The result is computed by
3324 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3325 // if (k < 0.0)
3326 // return genType(0.0)
3327 // else
3328 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3329 resultArray = new TConstantUnion[maxObjectSize];
3330 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3331 for (size_t i = 0; i < maxObjectSize; i++)
3332 {
3333 float eta = unionArrays[2][i].getFConst();
3334 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3335 if (k < 0.0f)
3336 resultArray[i].setFConst(0.0f);
3337 else
3338 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3339 (eta * dotProduct + sqrtf(k)) *
3340 unionArrays[1][i].getFConst());
3341 }
3342 break;
3343 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003344 case EOpBitfieldExtract:
3345 {
3346 resultArray = new TConstantUnion[maxObjectSize];
3347 for (size_t i = 0; i < maxObjectSize; ++i)
3348 {
3349 int offset = unionArrays[1][0].getIConst();
3350 int bits = unionArrays[2][0].getIConst();
3351 if (bits == 0)
3352 {
3353 if (aggregate->getBasicType() == EbtInt)
3354 {
3355 resultArray[i].setIConst(0);
3356 }
3357 else
3358 {
3359 ASSERT(aggregate->getBasicType() == EbtUInt);
3360 resultArray[i].setUConst(0);
3361 }
3362 }
3363 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3364 {
3365 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3366 &resultArray[i]);
3367 }
3368 else
3369 {
3370 // bits can be 32 here, so we need to avoid bit shift overflow.
3371 uint32_t maskMsb = 1u << (bits - 1);
3372 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3373 if (aggregate->getBasicType() == EbtInt)
3374 {
3375 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3376 uint32_t resultUnsigned = (value & mask) >> offset;
3377 if ((resultUnsigned & maskMsb) != 0)
3378 {
3379 // The most significant bits (from bits+1 to the most significant bit)
3380 // should be set to 1.
3381 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3382 resultUnsigned |= higherBitsMask;
3383 }
3384 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3385 }
3386 else
3387 {
3388 ASSERT(aggregate->getBasicType() == EbtUInt);
3389 uint32_t value = unionArrays[0][i].getUConst();
3390 resultArray[i].setUConst((value & mask) >> offset);
3391 }
3392 }
3393 }
3394 break;
3395 }
3396 case EOpBitfieldInsert:
3397 {
3398 resultArray = new TConstantUnion[maxObjectSize];
3399 for (size_t i = 0; i < maxObjectSize; ++i)
3400 {
3401 int offset = unionArrays[2][0].getIConst();
3402 int bits = unionArrays[3][0].getIConst();
3403 if (bits == 0)
3404 {
3405 if (aggregate->getBasicType() == EbtInt)
3406 {
3407 int32_t base = unionArrays[0][i].getIConst();
3408 resultArray[i].setIConst(base);
3409 }
3410 else
3411 {
3412 ASSERT(aggregate->getBasicType() == EbtUInt);
3413 uint32_t base = unionArrays[0][i].getUConst();
3414 resultArray[i].setUConst(base);
3415 }
3416 }
3417 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3418 {
3419 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3420 &resultArray[i]);
3421 }
3422 else
3423 {
3424 // bits can be 32 here, so we need to avoid bit shift overflow.
3425 uint32_t maskMsb = 1u << (bits - 1);
3426 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3427 uint32_t baseMask = ~insertMask;
3428 if (aggregate->getBasicType() == EbtInt)
3429 {
3430 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3431 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3432 uint32_t resultUnsigned =
3433 (base & baseMask) | ((insert << offset) & insertMask);
3434 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3435 }
3436 else
3437 {
3438 ASSERT(aggregate->getBasicType() == EbtUInt);
3439 uint32_t base = unionArrays[0][i].getUConst();
3440 uint32_t insert = unionArrays[1][i].getUConst();
3441 resultArray[i].setUConst((base & baseMask) |
3442 ((insert << offset) & insertMask));
3443 }
3444 }
3445 }
3446 break;
3447 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003448
3449 default:
3450 UNREACHABLE();
3451 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303452 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003453 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303454}
3455
Jamie Madill45bcc782016-11-07 13:58:48 -05003456} // namespace sh