blob: 61d4cf335c1f1c70b678bacc66e76bee19f183e6 [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{
267 return replaceChildNodeInternal(original, replacement);
268}
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 Etuaho16c745a2017-01-16 17:02:27 +0000692void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
693{
694 ASSERT(parameter != nullptr);
695 mParameters.push_back(parameter);
696}
697
Olli Etuaho13389b62016-10-16 11:48:18 +0100698void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
699{
700 ASSERT(declarator != nullptr);
701 ASSERT(declarator->getAsSymbolNode() != nullptr ||
702 (declarator->getAsBinaryNode() != nullptr &&
703 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
704 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300705 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100706 mDeclarators.push_back(declarator);
707}
708
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300709bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
710{
711 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
712 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
713 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
714 return false;
715}
716
Olli Etuaho57961272016-09-14 13:57:46 +0300717bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400718{
719 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100720 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
721 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400722 return false;
723}
724
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500725bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200726{
727 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100728 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300729 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200730 return false;
731}
732
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500733bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200734{
735 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
736 return false;
737}
738
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200739TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode()
Olli Etuahod7a25242015-08-18 13:49:45 +0300740{
741 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
742 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200743 // We need to manually copy any fields of TIntermNode.
Olli Etuahod7a25242015-08-18 13:49:45 +0300744 mLine = node.mLine;
745}
746
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200747bool TIntermTyped::hasConstantValue() const
Olli Etuahod4f4c112016-04-15 15:11:24 +0300748{
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200749 return false;
750}
751
752const TConstantUnion *TIntermTyped::getConstantValue() const
753{
754 return nullptr;
Olli Etuahod4f4c112016-04-15 15:11:24 +0300755}
756
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200757TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node)
758 : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300759{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200760 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300761}
762
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200763TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200764 : TIntermTyped(), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100765{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200766 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100767}
768
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200769const TType &TIntermFunctionPrototype::getType() const
770{
771 return mFunction->getReturnType();
772}
773
Olli Etuahod7a25242015-08-18 13:49:45 +0300774TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
775 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300776 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100777 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400778 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300779{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800780 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300781 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800782 TIntermTyped *typedArg = arg->getAsTyped();
783 ASSERT(typedArg != nullptr);
784 TIntermTyped *argCopy = typedArg->deepCopy();
785 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300786 }
787}
788
Olli Etuahofe486322017-03-21 09:30:54 +0000789TIntermAggregate *TIntermAggregate::shallowCopy() const
790{
791 TIntermSequence *copySeq = new TIntermSequence();
792 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400793 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000794 copyNode->setLine(mLine);
795 return copyNode;
796}
797
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200798TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermExpression(node)
Olli Etuahob6fa0432016-09-28 16:28:05 +0100799{
800 TIntermTyped *operandCopy = node.mOperand->deepCopy();
801 ASSERT(operandCopy != nullptr);
802 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000803 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100804}
805
Olli Etuahod7a25242015-08-18 13:49:45 +0300806TIntermBinary::TIntermBinary(const TIntermBinary &node)
807 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
808{
809 TIntermTyped *leftCopy = node.mLeft->deepCopy();
810 TIntermTyped *rightCopy = node.mRight->deepCopy();
811 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
812 mLeft = leftCopy;
813 mRight = rightCopy;
814}
815
816TIntermUnary::TIntermUnary(const TIntermUnary &node)
817 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
818{
819 TIntermTyped *operandCopy = node.mOperand->deepCopy();
820 ASSERT(operandCopy != nullptr);
821 mOperand = operandCopy;
822}
823
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200824TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300825{
Olli Etuahod7a25242015-08-18 13:49:45 +0300826 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300827 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
828 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300829 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300830 mCondition = conditionCopy;
831 mTrueExpression = trueCopy;
832 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300833}
834
Jamie Madillb1a85f42014-08-19 15:23:24 -0400835bool TIntermOperator::isAssignment() const
836{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300837 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400838}
839
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300840bool TIntermOperator::isMultiplication() const
841{
842 switch (mOp)
843 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500844 case EOpMul:
845 case EOpMatrixTimesMatrix:
846 case EOpMatrixTimesVector:
847 case EOpMatrixTimesScalar:
848 case EOpVectorTimesMatrix:
849 case EOpVectorTimesScalar:
850 return true;
851 default:
852 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300853 }
854}
855
Jamie Madillb1a85f42014-08-19 15:23:24 -0400856bool TIntermOperator::isConstructor() const
857{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300858 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400859}
860
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800861bool TIntermOperator::isFunctionCall() const
862{
863 switch (mOp)
864 {
865 case EOpCallFunctionInAST:
866 case EOpCallBuiltInFunction:
867 case EOpCallInternalRawFunction:
868 return true;
869 default:
870 return false;
871 }
872}
873
Olli Etuaho1dded802016-08-18 18:13:13 +0300874TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
875{
876 if (left.isMatrix())
877 {
878 if (right.isMatrix())
879 {
880 return EOpMatrixTimesMatrix;
881 }
882 else
883 {
884 if (right.isVector())
885 {
886 return EOpMatrixTimesVector;
887 }
888 else
889 {
890 return EOpMatrixTimesScalar;
891 }
892 }
893 }
894 else
895 {
896 if (right.isMatrix())
897 {
898 if (left.isVector())
899 {
900 return EOpVectorTimesMatrix;
901 }
902 else
903 {
904 return EOpMatrixTimesScalar;
905 }
906 }
907 else
908 {
909 // Neither operand is a matrix.
910 if (left.isVector() == right.isVector())
911 {
912 // Leave as component product.
913 return EOpMul;
914 }
915 else
916 {
917 return EOpVectorTimesScalar;
918 }
919 }
920 }
921}
922
923TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
924{
925 if (left.isMatrix())
926 {
927 if (right.isMatrix())
928 {
929 return EOpMatrixTimesMatrixAssign;
930 }
931 else
932 {
933 // right should be scalar, but this may not be validated yet.
934 return EOpMatrixTimesScalarAssign;
935 }
936 }
937 else
938 {
939 if (right.isMatrix())
940 {
941 // Left should be a vector, but this may not be validated yet.
942 return EOpVectorTimesMatrixAssign;
943 }
944 else
945 {
946 // Neither operand is a matrix.
947 if (left.isVector() == right.isVector())
948 {
949 // Leave as component product.
950 return EOpMulAssign;
951 }
952 else
953 {
954 // left should be vector and right should be scalar, but this may not be validated
955 // yet.
956 return EOpVectorTimesScalarAssign;
957 }
958 }
959 }
960}
961
Jamie Madillb1a85f42014-08-19 15:23:24 -0400962//
963// Make sure the type of a unary operator is appropriate for its
964// combination of operation and operand type.
965//
Olli Etuahoa2234302016-08-31 12:05:39 +0300966void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400967{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300968 if (mOp == EOpArrayLength)
969 {
970 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
971 setType(TType(EbtInt, EbpUndefined, EvqConst));
972 return;
973 }
974
Olli Etuahoa2234302016-08-31 12:05:39 +0300975 TQualifier resultQualifier = EvqTemporary;
976 if (mOperand->getQualifier() == EvqConst)
977 resultQualifier = EvqConst;
978
979 unsigned char operandPrimarySize =
980 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400981 switch (mOp)
982 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300983 case EOpFloatBitsToInt:
984 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
985 break;
986 case EOpFloatBitsToUint:
987 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
988 break;
989 case EOpIntBitsToFloat:
990 case EOpUintBitsToFloat:
991 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
992 break;
993 case EOpPackSnorm2x16:
994 case EOpPackUnorm2x16:
995 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800996 case EOpPackUnorm4x8:
997 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300998 setType(TType(EbtUInt, EbpHigh, resultQualifier));
999 break;
1000 case EOpUnpackSnorm2x16:
1001 case EOpUnpackUnorm2x16:
1002 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
1003 break;
1004 case EOpUnpackHalf2x16:
1005 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
1006 break;
Olli Etuaho25aef452017-01-29 16:15:44 -08001007 case EOpUnpackUnorm4x8:
1008 case EOpUnpackSnorm4x8:
1009 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
1010 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001011 case EOpAny:
1012 case EOpAll:
1013 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1014 break;
1015 case EOpLength:
1016 case EOpDeterminant:
1017 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
1018 break;
1019 case EOpTranspose:
1020 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
1021 static_cast<unsigned char>(mOperand->getType().getRows()),
1022 static_cast<unsigned char>(mOperand->getType().getCols())));
1023 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001024 case EOpIsinf:
1025 case EOpIsnan:
Olli Etuahoa2234302016-08-31 12:05:39 +03001026 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
1027 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001028 case EOpBitfieldReverse:
1029 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
1030 break;
1031 case EOpBitCount:
1032 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1033 break;
1034 case EOpFindLSB:
1035 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1036 break;
1037 case EOpFindMSB:
1038 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1039 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001040 default:
1041 setType(mOperand->getType());
1042 mType.setQualifier(resultQualifier);
1043 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001044 }
Olli Etuahoa2234302016-08-31 12:05:39 +03001045}
Jamie Madillb1a85f42014-08-19 15:23:24 -04001046
Olli Etuahob6fa0432016-09-28 16:28:05 +01001047TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001048 : TIntermExpression(TType(EbtFloat, EbpUndefined)),
Olli Etuahob6fa0432016-09-28 16:28:05 +01001049 mOperand(operand),
1050 mSwizzleOffsets(swizzleOffsets)
1051{
1052 ASSERT(mSwizzleOffsets.size() <= 4);
1053 promote();
1054}
1055
Olli Etuahoa2234302016-08-31 12:05:39 +03001056TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
1057 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
1058{
1059 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001060}
1061
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001062TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1063 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
1064{
1065 promote();
1066}
1067
Olli Etuaho0e99b7a2018-01-12 12:05:48 +02001068TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left,
1069 TIntermTyped *right,
1070 int shaderVersion)
1071{
1072 TIntermBinary *node = new TIntermBinary(EOpComma, left, right);
1073 node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right));
1074 return node;
1075}
1076
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001077TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1078 : TIntermNode(), mSymbol(symbol)
1079{
1080 ASSERT(symbol);
1081 setLine(line);
1082}
1083
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001084TIntermTernary::TIntermTernary(TIntermTyped *cond,
1085 TIntermTyped *trueExpression,
1086 TIntermTyped *falseExpression)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001087 : TIntermExpression(trueExpression->getType()),
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001088 mCondition(cond),
1089 mTrueExpression(trueExpression),
1090 mFalseExpression(falseExpression)
1091{
1092 getTypePointer()->setQualifier(
1093 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1094}
1095
Olli Etuaho81629262017-04-19 11:56:01 +03001096TIntermLoop::TIntermLoop(TLoopType type,
1097 TIntermNode *init,
1098 TIntermTyped *cond,
1099 TIntermTyped *expr,
1100 TIntermBlock *body)
1101 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1102{
1103 // Declaration nodes with no children can appear if all the declarators just added constants to
1104 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1105 if (mInit && mInit->getAsDeclarationNode() &&
1106 mInit->getAsDeclarationNode()->getSequence()->empty())
1107 {
1108 mInit = nullptr;
1109 }
1110}
1111
Olli Etuaho923ecef2017-10-11 12:01:38 +03001112TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
1113 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
1114{
1115 // Prune empty false blocks so that there won't be unnecessary operations done on it.
1116 if (mFalseBlock && mFalseBlock->getSequence()->empty())
1117 {
1118 mFalseBlock = nullptr;
1119 }
1120}
1121
1122TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
1123 : TIntermNode(), mInit(init), mStatementList(statementList)
1124{
1125 ASSERT(mStatementList);
1126}
1127
1128void TIntermSwitch::setStatementList(TIntermBlock *statementList)
1129{
1130 ASSERT(statementList);
1131 mStatementList = statementList;
1132}
1133
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001134// static
1135TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1136 TIntermTyped *trueExpression,
1137 TIntermTyped *falseExpression)
1138{
1139 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1140 falseExpression->getQualifier() == EvqConst)
1141 {
1142 return EvqConst;
1143 }
1144 return EvqTemporary;
1145}
1146
Olli Etuaho765924f2018-01-04 12:48:36 +02001147TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001148{
1149 if (mCondition->getAsConstantUnion())
1150 {
1151 if (mCondition->getAsConstantUnion()->getBConst(0))
1152 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001153 return mTrueExpression;
1154 }
1155 else
1156 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001157 return mFalseExpression;
1158 }
1159 }
1160 return this;
1161}
1162
Olli Etuahob6fa0432016-09-28 16:28:05 +01001163void TIntermSwizzle::promote()
1164{
1165 TQualifier resultQualifier = EvqTemporary;
1166 if (mOperand->getQualifier() == EvqConst)
1167 resultQualifier = EvqConst;
1168
1169 auto numFields = mSwizzleOffsets.size();
1170 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1171 static_cast<unsigned char>(numFields)));
1172}
1173
1174bool TIntermSwizzle::hasDuplicateOffsets() const
1175{
1176 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 Etuaho09b04a22016-12-15 13:30:26 +00001188bool TIntermSwizzle::offsetsMatch(int offset) const
1189{
1190 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1191}
1192
Olli Etuahob6fa0432016-09-28 16:28:05 +01001193void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1194{
1195 for (const int offset : mSwizzleOffsets)
1196 {
1197 switch (offset)
1198 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001199 case 0:
1200 *out << "x";
1201 break;
1202 case 1:
1203 *out << "y";
1204 break;
1205 case 2:
1206 *out << "z";
1207 break;
1208 case 3:
1209 *out << "w";
1210 break;
1211 default:
1212 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001213 }
1214 }
1215}
1216
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001217TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1218 const TIntermTyped *left,
1219 const TIntermTyped *right)
1220{
1221 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1222 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1223 right->getQualifier() != EvqConst)
1224 {
1225 return EvqTemporary;
1226 }
1227 return EvqConst;
1228}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001229
1230// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001231void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001232{
Olli Etuaho1dded802016-08-18 18:13:13 +03001233 ASSERT(!isMultiplication() ||
1234 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1235
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001236 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1237 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001238 if (mOp == EOpComma)
1239 {
1240 setType(mRight->getType());
1241 return;
1242 }
1243
Jamie Madillb1a85f42014-08-19 15:23:24 -04001244 // Base assumption: just make the type the same as the left
1245 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001246 setType(mLeft->getType());
1247
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001248 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001249 // Binary operations results in temporary variables unless both
1250 // operands are const.
1251 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1252 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001253 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001254 getTypePointer()->setQualifier(EvqTemporary);
1255 }
1256
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001257 // Handle indexing ops.
1258 switch (mOp)
1259 {
1260 case EOpIndexDirect:
1261 case EOpIndexIndirect:
1262 if (mLeft->isArray())
1263 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001264 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001265 }
1266 else if (mLeft->isMatrix())
1267 {
1268 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1269 static_cast<unsigned char>(mLeft->getRows())));
1270 }
1271 else if (mLeft->isVector())
1272 {
1273 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1274 }
1275 else
1276 {
1277 UNREACHABLE();
1278 }
1279 return;
1280 case EOpIndexDirectStruct:
1281 {
1282 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1283 const int i = mRight->getAsConstantUnion()->getIConst(0);
1284 setType(*fields[i]->type());
1285 getTypePointer()->setQualifier(resultQualifier);
1286 return;
1287 }
1288 case EOpIndexDirectInterfaceBlock:
1289 {
1290 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1291 const int i = mRight->getAsConstantUnion()->getIConst(0);
1292 setType(*fields[i]->type());
1293 getTypePointer()->setQualifier(resultQualifier);
1294 return;
1295 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001296 default:
1297 break;
1298 }
1299
1300 ASSERT(mLeft->isArray() == mRight->isArray());
1301
1302 // The result gets promoted to the highest precision.
1303 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1304 getTypePointer()->setPrecision(higherPrecision);
1305
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001306 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001307
1308 //
1309 // All scalars or structs. Code after this test assumes this case is removed!
1310 //
1311 if (nominalSize == 1)
1312 {
1313 switch (mOp)
1314 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001315 //
1316 // Promote to conditional
1317 //
1318 case EOpEqual:
1319 case EOpNotEqual:
1320 case EOpLessThan:
1321 case EOpGreaterThan:
1322 case EOpLessThanEqual:
1323 case EOpGreaterThanEqual:
1324 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1325 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001326
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001327 //
1328 // And and Or operate on conditionals
1329 //
1330 case EOpLogicalAnd:
1331 case EOpLogicalXor:
1332 case EOpLogicalOr:
1333 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1334 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1335 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001336
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001337 default:
1338 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001339 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001340 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001341 }
1342
1343 // If we reach here, at least one of the operands is vector or matrix.
1344 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001345 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001346
Jamie Madillb1a85f42014-08-19 15:23:24 -04001347 switch (mOp)
1348 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001349 case EOpMul:
1350 break;
1351 case EOpMatrixTimesScalar:
1352 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001353 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001354 setType(TType(basicType, higherPrecision, resultQualifier,
1355 static_cast<unsigned char>(mRight->getCols()),
1356 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001357 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001358 break;
1359 case EOpMatrixTimesVector:
1360 setType(TType(basicType, higherPrecision, resultQualifier,
1361 static_cast<unsigned char>(mLeft->getRows()), 1));
1362 break;
1363 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001364 setType(TType(basicType, higherPrecision, resultQualifier,
1365 static_cast<unsigned char>(mRight->getCols()),
1366 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001367 break;
1368 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001369 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001370 static_cast<unsigned char>(nominalSize), 1));
1371 break;
1372 case EOpVectorTimesMatrix:
1373 setType(TType(basicType, higherPrecision, resultQualifier,
1374 static_cast<unsigned char>(mRight->getCols()), 1));
1375 break;
1376 case EOpMulAssign:
1377 case EOpVectorTimesScalarAssign:
1378 case EOpVectorTimesMatrixAssign:
1379 case EOpMatrixTimesScalarAssign:
1380 case EOpMatrixTimesMatrixAssign:
1381 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1382 break;
1383 case EOpAssign:
1384 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001385 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1386 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1387 break;
1388 case EOpAdd:
1389 case EOpSub:
1390 case EOpDiv:
1391 case EOpIMod:
1392 case EOpBitShiftLeft:
1393 case EOpBitShiftRight:
1394 case EOpBitwiseAnd:
1395 case EOpBitwiseXor:
1396 case EOpBitwiseOr:
1397 case EOpAddAssign:
1398 case EOpSubAssign:
1399 case EOpDivAssign:
1400 case EOpIModAssign:
1401 case EOpBitShiftLeftAssign:
1402 case EOpBitShiftRightAssign:
1403 case EOpBitwiseAndAssign:
1404 case EOpBitwiseXorAssign:
1405 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001406 {
1407 const int secondarySize =
1408 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1409 setType(TType(basicType, higherPrecision, resultQualifier,
1410 static_cast<unsigned char>(nominalSize),
1411 static_cast<unsigned char>(secondarySize)));
1412 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001413 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001414 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001415 case EOpEqual:
1416 case EOpNotEqual:
1417 case EOpLessThan:
1418 case EOpGreaterThan:
1419 case EOpLessThanEqual:
1420 case EOpGreaterThanEqual:
1421 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1422 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001423 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001424 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001425
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001426 case EOpIndexDirect:
1427 case EOpIndexIndirect:
1428 case EOpIndexDirectInterfaceBlock:
1429 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001430 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001431 UNREACHABLE();
1432 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001433 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001434 UNREACHABLE();
1435 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001436 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001437}
1438
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001439bool TIntermConstantUnion::hasConstantValue() const
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001440{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001441 return true;
1442}
1443
1444const TConstantUnion *TIntermConstantUnion::getConstantValue() const
1445{
1446 return mUnionArrayPointer;
1447}
1448
1449const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
1450 const TConstantUnion *constArray,
1451 int index)
1452{
1453 if (type.isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001454 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001455 ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
1456 TType arrayElementType(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001457 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001458 size_t arrayElementSize = arrayElementType.getObjectSize();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001459 return &constArray[arrayElementSize * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001460 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001461 else if (type.isMatrix())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001462 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001463 ASSERT(index < type.getCols());
1464 int size = type.getRows();
1465 return &constArray[size * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001466 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001467 else if (type.isVector())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001468 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001469 ASSERT(index < type.getNominalSize());
1470 return &constArray[index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001471 }
1472 else
1473 {
1474 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001475 return nullptr;
1476 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001477}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001478
Olli Etuaho765924f2018-01-04 12:48:36 +02001479TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001480{
1481 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1482 if (operandConstant == nullptr)
1483 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001484 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001485 }
1486
1487 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1488 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1489 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001490 constArray[i] = *TIntermConstantUnion::FoldIndexing(
1491 operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
Olli Etuahob6fa0432016-09-28 16:28:05 +01001492 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001493 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001494}
1495
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001496TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1497{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001498 const TConstantUnion *rightConstant = mRight->getConstantValue();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001499 switch (mOp)
1500 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001501 case EOpComma:
1502 {
1503 if (mLeft->hasSideEffects())
1504 {
1505 return this;
1506 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001507 return mRight;
1508 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001509 case EOpIndexDirect:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001510 case EOpIndexDirectStruct:
1511 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001512 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001513 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001514 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001515 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001516 size_t index = static_cast<size_t>(rightConstant->getIConst());
1517 TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
1518 if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
1519 !leftAggregate->hasSideEffects())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001520 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001521 ASSERT(index < leftAggregate->getSequence()->size());
1522 // This transformation can't add complexity as we're eliminating the constructor
1523 // entirely.
1524 return leftAggregate->getSequence()->at(index)->getAsTyped();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001525 }
1526
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001527 // If the indexed value is already a constant union, we can't increase duplication of
1528 // data by folding the indexing. Also fold the node in case it's generally beneficial to
1529 // replace this type of node with a constant union even if that would mean duplicating
1530 // data.
1531 if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
1532 {
1533 const TConstantUnion *constantValue = getConstantValue();
1534 if (constantValue == nullptr)
1535 {
1536 return this;
1537 }
1538 return CreateFoldedNode(constantValue, this);
1539 }
1540 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001541 }
1542 case EOpIndexIndirect:
1543 case EOpIndexDirectInterfaceBlock:
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001544 case EOpInitialize:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001545 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001546 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001547 default:
1548 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001549 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001550 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001551 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001552 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001553 const TConstantUnion *leftConstant = mLeft->getConstantValue();
1554 if (leftConstant == nullptr)
1555 {
1556 return this;
1557 }
1558 const TConstantUnion *constArray =
1559 TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
1560 mRight->getType(), diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001561 if (!constArray)
1562 {
1563 return this;
1564 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001565 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001566 }
1567 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001568}
1569
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001570bool TIntermBinary::hasConstantValue() const
1571{
1572 switch (mOp)
1573 {
1574 case EOpIndexDirect:
1575 case EOpIndexDirectStruct:
1576 {
1577 if (mLeft->hasConstantValue() && mRight->hasConstantValue())
1578 {
1579 return true;
1580 }
Nico Weber41b072b2018-02-09 10:01:32 -05001581 break;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001582 }
1583 default:
1584 break;
1585 }
1586 return false;
1587}
1588
1589const TConstantUnion *TIntermBinary::getConstantValue() const
1590{
1591 if (!hasConstantValue())
1592 {
1593 return nullptr;
1594 }
1595
1596 const TConstantUnion *leftConstantValue = mLeft->getConstantValue();
1597 int index = mRight->getConstantValue()->getIConst();
1598 const TConstantUnion *constIndexingResult = nullptr;
1599 if (mOp == EOpIndexDirect)
1600 {
1601 constIndexingResult =
1602 TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
1603 }
1604 else
1605 {
1606 ASSERT(mOp == EOpIndexDirectStruct);
1607 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1608
1609 size_t previousFieldsSize = 0;
1610 for (int i = 0; i < index; ++i)
1611 {
1612 previousFieldsSize += fields[i]->type()->getObjectSize();
1613 }
1614 constIndexingResult = leftConstantValue + previousFieldsSize;
1615 }
1616 return constIndexingResult;
1617}
1618
Olli Etuahof119a262016-08-19 15:54:22 +03001619TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001620{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301621 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001622
1623 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301624 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001625 // The size of runtime-sized arrays may only be determined at runtime.
1626 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001627 {
1628 return this;
1629 }
1630 constArray = new TConstantUnion[1];
1631 constArray->setIConst(mOperand->getOutermostArraySize());
1632 }
1633 else
1634 {
1635 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1636 if (operandConstant == nullptr)
1637 {
1638 return this;
1639 }
1640
1641 switch (mOp)
1642 {
1643 case EOpAny:
1644 case EOpAll:
1645 case EOpLength:
1646 case EOpTranspose:
1647 case EOpDeterminant:
1648 case EOpInverse:
1649 case EOpPackSnorm2x16:
1650 case EOpUnpackSnorm2x16:
1651 case EOpPackUnorm2x16:
1652 case EOpUnpackUnorm2x16:
1653 case EOpPackHalf2x16:
1654 case EOpUnpackHalf2x16:
1655 case EOpPackUnorm4x8:
1656 case EOpPackSnorm4x8:
1657 case EOpUnpackUnorm4x8:
1658 case EOpUnpackSnorm4x8:
1659 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1660 break;
1661 default:
1662 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1663 break;
1664 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301665 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001666 if (constArray == nullptr)
1667 {
1668 return this;
1669 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001670 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001671}
1672
Olli Etuahof119a262016-08-19 15:54:22 +03001673TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001674{
1675 // Make sure that all params are constant before actual constant folding.
1676 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001677 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001678 if (param->getAsConstantUnion() == nullptr)
1679 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001680 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001681 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001682 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001683 const TConstantUnion *constArray = nullptr;
Olli Etuaho1d122782015-11-06 15:35:17 +02001684 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001685 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001686 if (mType.canReplaceWithConstantUnion())
Olli Etuaho765924f2018-01-04 12:48:36 +02001687 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001688 constArray = getConstantValue();
Olli Etuaho765924f2018-01-04 12:48:36 +02001689 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001690 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001691 else if (CanFoldAggregateBuiltInOp(mOp))
Olli Etuaho2768bc82017-12-12 11:51:48 +02001692 {
Olli Etuahof119a262016-08-19 15:54:22 +03001693 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001694 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001695 if (constArray == nullptr)
1696 {
1697 return this;
1698 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001699 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001700}
1701
Jamie Madillb1a85f42014-08-19 15:23:24 -04001702//
1703// The fold functions see if an operation on a constant can be done in place,
1704// without generating run-time code.
1705//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001706// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001707//
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001708const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
1709 const TConstantUnion *leftArray,
1710 const TType &leftType,
1711 const TConstantUnion *rightArray,
1712 const TType &rightType,
1713 TDiagnostics *diagnostics,
1714 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001715{
Olli Etuahof119a262016-08-19 15:54:22 +03001716 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001717
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001718 size_t objectSize = leftType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001719
1720 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001721 if (rightType.getObjectSize() == 1 && objectSize > 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001722 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001723 rightArray = Vectorize(*rightArray, objectSize);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001724 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001725 else if (rightType.getObjectSize() > 1 && objectSize == 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001726 {
1727 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001728 leftArray = Vectorize(*leftArray, rightType.getObjectSize());
1729 objectSize = rightType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001730 }
1731
1732 TConstantUnion *resultArray = nullptr;
1733
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001734 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001735 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001736 case EOpAdd:
1737 resultArray = new TConstantUnion[objectSize];
1738 for (size_t i = 0; i < objectSize; i++)
1739 resultArray[i] =
1740 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1741 break;
1742 case EOpSub:
1743 resultArray = new TConstantUnion[objectSize];
1744 for (size_t i = 0; i < objectSize; i++)
1745 resultArray[i] =
1746 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1747 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001748
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001749 case EOpMul:
1750 case EOpVectorTimesScalar:
1751 case EOpMatrixTimesScalar:
1752 resultArray = new TConstantUnion[objectSize];
1753 for (size_t i = 0; i < objectSize; i++)
1754 resultArray[i] =
1755 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1756 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001757
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001758 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001759 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001760 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001761 ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001762
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001763 const int leftCols = leftType.getCols();
1764 const int leftRows = leftType.getRows();
1765 const int rightCols = rightType.getCols();
1766 const int rightRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001767 const int resultCols = rightCols;
1768 const int resultRows = leftRows;
1769
1770 resultArray = new TConstantUnion[resultCols * resultRows];
1771 for (int row = 0; row < resultRows; row++)
1772 {
1773 for (int column = 0; column < resultCols; column++)
1774 {
1775 resultArray[resultRows * column + row].setFConst(0.0f);
1776 for (int i = 0; i < leftCols; i++)
1777 {
1778 resultArray[resultRows * column + row].setFConst(
1779 resultArray[resultRows * column + row].getFConst() +
1780 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001781 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001782 }
1783 }
1784 }
1785 }
1786 break;
1787
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001788 case EOpDiv:
1789 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001790 {
1791 resultArray = new TConstantUnion[objectSize];
1792 for (size_t i = 0; i < objectSize; i++)
1793 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001794 switch (leftType.getBasicType())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001795 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001796 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001797 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001798 ASSERT(op == EOpDiv);
1799 float dividend = leftArray[i].getFConst();
1800 float divisor = rightArray[i].getFConst();
1801 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001802 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001803 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001804 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001805 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001806 line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001807 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001808 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001809 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001810 }
1811 else
1812 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001813 diagnostics->warning(line, "Divide by zero during constant folding",
1814 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001815 bool negativeResult =
1816 std::signbit(dividend) != std::signbit(divisor);
1817 resultArray[i].setFConst(
1818 negativeResult ? -std::numeric_limits<float>::infinity()
1819 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001820 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001821 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001822 else if (gl::isInf(dividend) && gl::isInf(divisor))
1823 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001824 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001825 "Infinity divided by infinity during constant "
1826 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001827 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001828 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1829 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001830 else
1831 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001832 float result = dividend / divisor;
1833 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001834 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001835 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001836 line, "Constant folded division overflowed to infinity", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001837 }
1838 resultArray[i].setFConst(result);
1839 }
1840 break;
1841 }
1842 case EbtInt:
1843 if (rightArray[i] == 0)
1844 {
1845 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001846 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001847 resultArray[i].setIConst(INT_MAX);
1848 }
1849 else
1850 {
1851 int lhs = leftArray[i].getIConst();
1852 int divisor = rightArray[i].getIConst();
1853 if (op == EOpDiv)
1854 {
1855 // Check for the special case where the minimum representable number
1856 // is
1857 // divided by -1. If left alone this leads to integer overflow in
1858 // C++.
1859 // ESSL 3.00.6 section 4.1.3 Integers:
1860 // "However, for the case where the minimum representable value is
1861 // divided by -1, it is allowed to return either the minimum
1862 // representable value or the maximum representable value."
1863 if (lhs == -0x7fffffff - 1 && divisor == -1)
1864 {
1865 resultArray[i].setIConst(0x7fffffff);
1866 }
1867 else
1868 {
1869 resultArray[i].setIConst(lhs / divisor);
1870 }
Olli Etuahod4453572016-09-27 13:21:46 +01001871 }
1872 else
1873 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001874 ASSERT(op == EOpIMod);
1875 if (lhs < 0 || divisor < 0)
1876 {
1877 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1878 // when
1879 // either one of the operands is negative.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001880 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001881 "Negative modulus operator operand "
1882 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001883 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001884 resultArray[i].setIConst(0);
1885 }
1886 else
1887 {
1888 resultArray[i].setIConst(lhs % divisor);
1889 }
Olli Etuahod4453572016-09-27 13:21:46 +01001890 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001891 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001892 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001893
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001894 case EbtUInt:
1895 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001896 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001897 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001898 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001899 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001900 }
1901 else
1902 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001903 if (op == EOpDiv)
1904 {
1905 resultArray[i].setUConst(leftArray[i].getUConst() /
1906 rightArray[i].getUConst());
1907 }
1908 else
1909 {
1910 ASSERT(op == EOpIMod);
1911 resultArray[i].setUConst(leftArray[i].getUConst() %
1912 rightArray[i].getUConst());
1913 }
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 default:
1918 UNREACHABLE();
1919 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001920 }
1921 }
1922 }
1923 break;
1924
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001925 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001926 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001927 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001928 ASSERT(rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001929
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001930 const int matrixCols = leftType.getCols();
1931 const int matrixRows = leftType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001932
1933 resultArray = new TConstantUnion[matrixRows];
1934
1935 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1936 {
1937 resultArray[matrixRow].setFConst(0.0f);
1938 for (int col = 0; col < matrixCols; col++)
1939 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001940 resultArray[matrixRow].setFConst(
1941 resultArray[matrixRow].getFConst() +
1942 leftArray[col * matrixRows + matrixRow].getFConst() *
1943 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001944 }
1945 }
1946 }
1947 break;
1948
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001949 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001950 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001951 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001952 ASSERT(leftType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001953
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001954 const int matrixCols = rightType.getCols();
1955 const int matrixRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001956
1957 resultArray = new TConstantUnion[matrixCols];
1958
1959 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1960 {
1961 resultArray[matrixCol].setFConst(0.0f);
1962 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1963 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001964 resultArray[matrixCol].setFConst(
1965 resultArray[matrixCol].getFConst() +
1966 leftArray[matrixRow].getFConst() *
1967 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001968 }
1969 }
1970 }
1971 break;
1972
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001973 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001974 {
1975 resultArray = new TConstantUnion[objectSize];
1976 for (size_t i = 0; i < objectSize; i++)
1977 {
1978 resultArray[i] = leftArray[i] && rightArray[i];
1979 }
1980 }
1981 break;
1982
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001983 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001984 {
1985 resultArray = new TConstantUnion[objectSize];
1986 for (size_t i = 0; i < objectSize; i++)
1987 {
1988 resultArray[i] = leftArray[i] || rightArray[i];
1989 }
1990 }
1991 break;
1992
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001993 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001994 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001995 ASSERT(leftType.getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001996 resultArray = new TConstantUnion[objectSize];
1997 for (size_t i = 0; i < objectSize; i++)
1998 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001999 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002000 }
2001 }
2002 break;
2003
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002004 case EOpBitwiseAnd:
2005 resultArray = new TConstantUnion[objectSize];
2006 for (size_t i = 0; i < objectSize; i++)
2007 resultArray[i] = leftArray[i] & rightArray[i];
2008 break;
2009 case EOpBitwiseXor:
2010 resultArray = new TConstantUnion[objectSize];
2011 for (size_t i = 0; i < objectSize; i++)
2012 resultArray[i] = leftArray[i] ^ rightArray[i];
2013 break;
2014 case EOpBitwiseOr:
2015 resultArray = new TConstantUnion[objectSize];
2016 for (size_t i = 0; i < objectSize; i++)
2017 resultArray[i] = leftArray[i] | rightArray[i];
2018 break;
2019 case EOpBitShiftLeft:
2020 resultArray = new TConstantUnion[objectSize];
2021 for (size_t i = 0; i < objectSize; i++)
2022 resultArray[i] =
2023 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
2024 break;
2025 case EOpBitShiftRight:
2026 resultArray = new TConstantUnion[objectSize];
2027 for (size_t i = 0; i < objectSize; i++)
2028 resultArray[i] =
2029 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
2030 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002031
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002032 case EOpLessThan:
2033 ASSERT(objectSize == 1);
2034 resultArray = new TConstantUnion[1];
2035 resultArray->setBConst(*leftArray < *rightArray);
2036 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002037
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002038 case EOpGreaterThan:
2039 ASSERT(objectSize == 1);
2040 resultArray = new TConstantUnion[1];
2041 resultArray->setBConst(*leftArray > *rightArray);
2042 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002043
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002044 case EOpLessThanEqual:
2045 ASSERT(objectSize == 1);
2046 resultArray = new TConstantUnion[1];
2047 resultArray->setBConst(!(*leftArray > *rightArray));
2048 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002049
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002050 case EOpGreaterThanEqual:
2051 ASSERT(objectSize == 1);
2052 resultArray = new TConstantUnion[1];
2053 resultArray->setBConst(!(*leftArray < *rightArray));
2054 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002055
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002056 case EOpEqual:
2057 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002058 {
2059 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002060 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002061 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002062 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002063 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002064 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002065 equal = false;
2066 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002067 }
2068 }
2069 if (op == EOpEqual)
2070 {
2071 resultArray->setBConst(equal);
2072 }
2073 else
2074 {
2075 resultArray->setBConst(!equal);
2076 }
2077 }
2078 break;
2079
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002080 default:
2081 UNREACHABLE();
2082 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002083 }
2084 return resultArray;
2085}
2086
Olli Etuahof119a262016-08-19 15:54:22 +03002087// The fold functions do operations on a constant at GLSL compile time, without generating run-time
2088// code. Returns the constant value to keep using. Nullptr should not be returned.
2089TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04002090{
Olli Etuahof119a262016-08-19 15:54:22 +03002091 // Do operations where the return type may have a different number of components compared to the
2092 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04002093
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002094 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002095 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302096
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002097 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302098 TConstantUnion *resultArray = nullptr;
2099 switch (op)
2100 {
Olli Etuahof119a262016-08-19 15:54:22 +03002101 case EOpAny:
2102 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302103 resultArray = new TConstantUnion();
2104 resultArray->setBConst(false);
2105 for (size_t i = 0; i < objectSize; i++)
2106 {
2107 if (operandArray[i].getBConst())
2108 {
2109 resultArray->setBConst(true);
2110 break;
2111 }
2112 }
2113 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302114
Olli Etuahof119a262016-08-19 15:54:22 +03002115 case EOpAll:
2116 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302117 resultArray = new TConstantUnion();
2118 resultArray->setBConst(true);
2119 for (size_t i = 0; i < objectSize; i++)
2120 {
2121 if (!operandArray[i].getBConst())
2122 {
2123 resultArray->setBConst(false);
2124 break;
2125 }
2126 }
2127 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302128
Olli Etuahof119a262016-08-19 15:54:22 +03002129 case EOpLength:
2130 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302131 resultArray = new TConstantUnion();
2132 resultArray->setFConst(VectorLength(operandArray, objectSize));
2133 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302134
Olli Etuahof119a262016-08-19 15:54:22 +03002135 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136 {
Olli Etuahof119a262016-08-19 15:54:22 +03002137 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302138 resultArray = new TConstantUnion[objectSize];
2139 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002140 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302141 SetUnionArrayFromMatrix(result, resultArray);
2142 break;
2143 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302144
Olli Etuahof119a262016-08-19 15:54:22 +03002145 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302146 {
Olli Etuahof119a262016-08-19 15:54:22 +03002147 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302148 unsigned int size = getType().getNominalSize();
2149 ASSERT(size >= 2 && size <= 4);
2150 resultArray = new TConstantUnion();
2151 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
2152 break;
2153 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302154
Olli Etuahof119a262016-08-19 15:54:22 +03002155 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302156 {
Olli Etuahof119a262016-08-19 15:54:22 +03002157 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302158 unsigned int size = getType().getNominalSize();
2159 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03002160 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05302161 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
2162 SetUnionArrayFromMatrix(result, resultArray);
2163 break;
2164 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302165
Olli Etuahof119a262016-08-19 15:54:22 +03002166 case EOpPackSnorm2x16:
2167 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302168 ASSERT(getType().getNominalSize() == 2);
2169 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002170 resultArray->setUConst(
2171 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302172 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302173
Olli Etuahof119a262016-08-19 15:54:22 +03002174 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302175 {
Olli Etuahof119a262016-08-19 15:54:22 +03002176 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302177 resultArray = new TConstantUnion[2];
2178 float f1, f2;
2179 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2180 resultArray[0].setFConst(f1);
2181 resultArray[1].setFConst(f2);
2182 break;
2183 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302184
Olli Etuahof119a262016-08-19 15:54:22 +03002185 case EOpPackUnorm2x16:
2186 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302187 ASSERT(getType().getNominalSize() == 2);
2188 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002189 resultArray->setUConst(
2190 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302191 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302192
Olli Etuahof119a262016-08-19 15:54:22 +03002193 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302194 {
Olli Etuahof119a262016-08-19 15:54:22 +03002195 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302196 resultArray = new TConstantUnion[2];
2197 float f1, f2;
2198 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2199 resultArray[0].setFConst(f1);
2200 resultArray[1].setFConst(f2);
2201 break;
2202 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302203
Olli Etuahof119a262016-08-19 15:54:22 +03002204 case EOpPackHalf2x16:
2205 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302206 ASSERT(getType().getNominalSize() == 2);
2207 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002208 resultArray->setUConst(
2209 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302210 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302211
Olli Etuahof119a262016-08-19 15:54:22 +03002212 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302213 {
Olli Etuahof119a262016-08-19 15:54:22 +03002214 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302215 resultArray = new TConstantUnion[2];
2216 float f1, f2;
2217 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2218 resultArray[0].setFConst(f1);
2219 resultArray[1].setFConst(f2);
2220 break;
2221 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302222
Olli Etuaho25aef452017-01-29 16:15:44 -08002223 case EOpPackUnorm4x8:
2224 {
2225 ASSERT(getType().getBasicType() == EbtFloat);
2226 resultArray = new TConstantUnion();
2227 resultArray->setUConst(
2228 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2229 operandArray[2].getFConst(), operandArray[3].getFConst()));
2230 break;
2231 }
2232 case EOpPackSnorm4x8:
2233 {
2234 ASSERT(getType().getBasicType() == EbtFloat);
2235 resultArray = new TConstantUnion();
2236 resultArray->setUConst(
2237 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2238 operandArray[2].getFConst(), operandArray[3].getFConst()));
2239 break;
2240 }
2241 case EOpUnpackUnorm4x8:
2242 {
2243 ASSERT(getType().getBasicType() == EbtUInt);
2244 resultArray = new TConstantUnion[4];
2245 float f[4];
2246 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2247 for (size_t i = 0; i < 4; ++i)
2248 {
2249 resultArray[i].setFConst(f[i]);
2250 }
2251 break;
2252 }
2253 case EOpUnpackSnorm4x8:
2254 {
2255 ASSERT(getType().getBasicType() == EbtUInt);
2256 resultArray = new TConstantUnion[4];
2257 float f[4];
2258 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2259 for (size_t i = 0; i < 4; ++i)
2260 {
2261 resultArray[i].setFConst(f[i]);
2262 }
2263 break;
2264 }
2265
Olli Etuahof119a262016-08-19 15:54:22 +03002266 default:
2267 UNREACHABLE();
2268 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302269 }
2270
2271 return resultArray;
2272}
2273
Olli Etuahof119a262016-08-19 15:54:22 +03002274TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2275 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302276{
Olli Etuahof119a262016-08-19 15:54:22 +03002277 // Do unary operations where each component of the result is computed based on the corresponding
2278 // component of the operand. Also folds normalize, though the divisor in that case takes all
2279 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302280
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002281 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002282 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002283
2284 size_t objectSize = getType().getObjectSize();
2285
Arun Patoleab2b9a22015-07-06 18:27:56 +05302286 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2287 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302288 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002289 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302290 {
Olli Etuahof119a262016-08-19 15:54:22 +03002291 case EOpNegative:
2292 switch (getType().getBasicType())
2293 {
2294 case EbtFloat:
2295 resultArray[i].setFConst(-operandArray[i].getFConst());
2296 break;
2297 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002298 if (operandArray[i] == std::numeric_limits<int>::min())
2299 {
2300 // The minimum representable integer doesn't have a positive
2301 // counterpart, rather the negation overflows and in ESSL is supposed to
2302 // wrap back to the minimum representable integer. Make sure that we
2303 // don't actually let the negation overflow, which has undefined
2304 // behavior in C++.
2305 resultArray[i].setIConst(std::numeric_limits<int>::min());
2306 }
2307 else
2308 {
2309 resultArray[i].setIConst(-operandArray[i].getIConst());
2310 }
Olli Etuahof119a262016-08-19 15:54:22 +03002311 break;
2312 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002313 if (operandArray[i] == 0x80000000u)
2314 {
2315 resultArray[i].setUConst(0x80000000u);
2316 }
2317 else
2318 {
2319 resultArray[i].setUConst(static_cast<unsigned int>(
2320 -static_cast<int>(operandArray[i].getUConst())));
2321 }
Olli Etuahof119a262016-08-19 15:54:22 +03002322 break;
2323 default:
2324 UNREACHABLE();
2325 return nullptr;
2326 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302327 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302328
Olli Etuahof119a262016-08-19 15:54:22 +03002329 case EOpPositive:
2330 switch (getType().getBasicType())
2331 {
2332 case EbtFloat:
2333 resultArray[i].setFConst(operandArray[i].getFConst());
2334 break;
2335 case EbtInt:
2336 resultArray[i].setIConst(operandArray[i].getIConst());
2337 break;
2338 case EbtUInt:
2339 resultArray[i].setUConst(static_cast<unsigned int>(
2340 static_cast<int>(operandArray[i].getUConst())));
2341 break;
2342 default:
2343 UNREACHABLE();
2344 return nullptr;
2345 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302346 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302347
Olli Etuahof119a262016-08-19 15:54:22 +03002348 case EOpLogicalNot:
2349 switch (getType().getBasicType())
2350 {
2351 case EbtBool:
2352 resultArray[i].setBConst(!operandArray[i].getBConst());
2353 break;
2354 default:
2355 UNREACHABLE();
2356 return nullptr;
2357 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302358 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302359
Olli Etuahof119a262016-08-19 15:54:22 +03002360 case EOpBitwiseNot:
2361 switch (getType().getBasicType())
2362 {
2363 case EbtInt:
2364 resultArray[i].setIConst(~operandArray[i].getIConst());
2365 break;
2366 case EbtUInt:
2367 resultArray[i].setUConst(~operandArray[i].getUConst());
2368 break;
2369 default:
2370 UNREACHABLE();
2371 return nullptr;
2372 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302373 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302374
Olli Etuahof119a262016-08-19 15:54:22 +03002375 case EOpRadians:
2376 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302377 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2378 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302379
Olli Etuahof119a262016-08-19 15:54:22 +03002380 case EOpDegrees:
2381 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302382 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2383 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302384
Olli Etuahof119a262016-08-19 15:54:22 +03002385 case EOpSin:
2386 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302387 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302388
Olli Etuahof119a262016-08-19 15:54:22 +03002389 case EOpCos:
2390 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2391 break;
2392
2393 case EOpTan:
2394 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2395 break;
2396
2397 case EOpAsin:
2398 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2399 // 0.
2400 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2401 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2402 diagnostics, &resultArray[i]);
2403 else
2404 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2405 break;
2406
2407 case EOpAcos:
2408 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2409 // 0.
2410 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2411 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2412 diagnostics, &resultArray[i]);
2413 else
2414 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2415 break;
2416
2417 case EOpAtan:
2418 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2419 break;
2420
2421 case EOpSinh:
2422 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2423 break;
2424
2425 case EOpCosh:
2426 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2427 break;
2428
2429 case EOpTanh:
2430 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2431 break;
2432
2433 case EOpAsinh:
2434 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2435 break;
2436
2437 case EOpAcosh:
2438 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2439 if (operandArray[i].getFConst() < 1.0f)
2440 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2441 diagnostics, &resultArray[i]);
2442 else
2443 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2444 break;
2445
2446 case EOpAtanh:
2447 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2448 // 0.
2449 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2450 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2451 diagnostics, &resultArray[i]);
2452 else
2453 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2454 break;
2455
2456 case EOpAbs:
2457 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302458 {
Olli Etuahof119a262016-08-19 15:54:22 +03002459 case EbtFloat:
2460 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2461 break;
2462 case EbtInt:
2463 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2464 break;
2465 default:
2466 UNREACHABLE();
2467 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302468 }
2469 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002470
2471 case EOpSign:
2472 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302473 {
Olli Etuahof119a262016-08-19 15:54:22 +03002474 case EbtFloat:
2475 {
2476 float fConst = operandArray[i].getFConst();
2477 float fResult = 0.0f;
2478 if (fConst > 0.0f)
2479 fResult = 1.0f;
2480 else if (fConst < 0.0f)
2481 fResult = -1.0f;
2482 resultArray[i].setFConst(fResult);
2483 break;
2484 }
2485 case EbtInt:
2486 {
2487 int iConst = operandArray[i].getIConst();
2488 int iResult = 0;
2489 if (iConst > 0)
2490 iResult = 1;
2491 else if (iConst < 0)
2492 iResult = -1;
2493 resultArray[i].setIConst(iResult);
2494 break;
2495 }
2496 default:
2497 UNREACHABLE();
2498 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302499 }
2500 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302501
Olli Etuahof119a262016-08-19 15:54:22 +03002502 case EOpFloor:
2503 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2504 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302505
Olli Etuahof119a262016-08-19 15:54:22 +03002506 case EOpTrunc:
2507 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2508 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302509
Olli Etuahof119a262016-08-19 15:54:22 +03002510 case EOpRound:
2511 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2512 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302513
Olli Etuahof119a262016-08-19 15:54:22 +03002514 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302515 {
Olli Etuahof119a262016-08-19 15:54:22 +03002516 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302517 float x = operandArray[i].getFConst();
2518 float result;
2519 float fractPart = modff(x, &result);
2520 if (fabsf(fractPart) == 0.5f)
2521 result = 2.0f * roundf(x / 2.0f);
2522 else
2523 result = roundf(x);
2524 resultArray[i].setFConst(result);
2525 break;
2526 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302527
Olli Etuahof119a262016-08-19 15:54:22 +03002528 case EOpCeil:
2529 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2530 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302531
Olli Etuahof119a262016-08-19 15:54:22 +03002532 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302533 {
Olli Etuahof119a262016-08-19 15:54:22 +03002534 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302535 float x = operandArray[i].getFConst();
2536 resultArray[i].setFConst(x - floorf(x));
2537 break;
2538 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302539
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002540 case EOpIsnan:
Olli Etuahof119a262016-08-19 15:54:22 +03002541 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302542 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2543 break;
Arun Patole551279e2015-07-07 18:18:23 +05302544
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002545 case EOpIsinf:
Olli Etuahof119a262016-08-19 15:54:22 +03002546 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302547 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2548 break;
Arun Patole551279e2015-07-07 18:18:23 +05302549
Olli Etuahof119a262016-08-19 15:54:22 +03002550 case EOpFloatBitsToInt:
2551 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302552 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2553 break;
Arun Patole551279e2015-07-07 18:18:23 +05302554
Olli Etuahof119a262016-08-19 15:54:22 +03002555 case EOpFloatBitsToUint:
2556 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302557 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2558 break;
Arun Patole551279e2015-07-07 18:18:23 +05302559
Olli Etuahof119a262016-08-19 15:54:22 +03002560 case EOpIntBitsToFloat:
2561 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302562 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2563 break;
Arun Patole551279e2015-07-07 18:18:23 +05302564
Olli Etuahof119a262016-08-19 15:54:22 +03002565 case EOpUintBitsToFloat:
2566 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302567 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2568 break;
Arun Patole551279e2015-07-07 18:18:23 +05302569
Olli Etuahof119a262016-08-19 15:54:22 +03002570 case EOpExp:
2571 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2572 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302573
Olli Etuahof119a262016-08-19 15:54:22 +03002574 case EOpLog:
2575 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2576 if (operandArray[i].getFConst() <= 0.0f)
2577 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2578 diagnostics, &resultArray[i]);
2579 else
2580 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2581 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302582
Olli Etuahof119a262016-08-19 15:54:22 +03002583 case EOpExp2:
2584 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2585 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302586
Olli Etuahof119a262016-08-19 15:54:22 +03002587 case EOpLog2:
2588 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2589 // And log2f is not available on some plarforms like old android, so just using
2590 // log(x)/log(2) here.
2591 if (operandArray[i].getFConst() <= 0.0f)
2592 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2593 diagnostics, &resultArray[i]);
2594 else
2595 {
2596 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2597 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2598 }
2599 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302600
Olli Etuahof119a262016-08-19 15:54:22 +03002601 case EOpSqrt:
2602 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2603 if (operandArray[i].getFConst() < 0.0f)
2604 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2605 diagnostics, &resultArray[i]);
2606 else
2607 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2608 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302609
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002610 case EOpInversesqrt:
Olli Etuahof119a262016-08-19 15:54:22 +03002611 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2612 // so getting the square root first using builtin function sqrt() and then taking
2613 // its inverse.
2614 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2615 // result to 0.
2616 if (operandArray[i].getFConst() <= 0.0f)
2617 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2618 diagnostics, &resultArray[i]);
2619 else
2620 {
2621 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2622 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2623 }
2624 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302625
Olli Etuahod68924e2017-01-02 17:34:40 +00002626 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002627 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302628 resultArray[i].setBConst(!operandArray[i].getBConst());
2629 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302630
Olli Etuahof119a262016-08-19 15:54:22 +03002631 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302632 {
Olli Etuahof119a262016-08-19 15:54:22 +03002633 ASSERT(getType().getBasicType() == EbtFloat);
2634 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302635 float length = VectorLength(operandArray, objectSize);
2636 if (length)
2637 resultArray[i].setFConst(x / length);
2638 else
Olli Etuahof119a262016-08-19 15:54:22 +03002639 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2640 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302641 break;
2642 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002643 case EOpBitfieldReverse:
2644 {
2645 uint32_t value;
2646 if (getType().getBasicType() == EbtInt)
2647 {
2648 value = static_cast<uint32_t>(operandArray[i].getIConst());
2649 }
2650 else
2651 {
2652 ASSERT(getType().getBasicType() == EbtUInt);
2653 value = operandArray[i].getUConst();
2654 }
2655 uint32_t result = gl::BitfieldReverse(value);
2656 if (getType().getBasicType() == EbtInt)
2657 {
2658 resultArray[i].setIConst(static_cast<int32_t>(result));
2659 }
2660 else
2661 {
2662 resultArray[i].setUConst(result);
2663 }
2664 break;
2665 }
2666 case EOpBitCount:
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 int result = gl::BitCount(value);
2679 resultArray[i].setIConst(result);
2680 break;
2681 }
2682 case EOpFindLSB:
2683 {
2684 uint32_t value;
2685 if (getType().getBasicType() == EbtInt)
2686 {
2687 value = static_cast<uint32_t>(operandArray[i].getIConst());
2688 }
2689 else
2690 {
2691 ASSERT(getType().getBasicType() == EbtUInt);
2692 value = operandArray[i].getUConst();
2693 }
2694 resultArray[i].setIConst(gl::FindLSB(value));
2695 break;
2696 }
2697 case EOpFindMSB:
2698 {
2699 uint32_t value;
2700 if (getType().getBasicType() == EbtInt)
2701 {
2702 int intValue = operandArray[i].getIConst();
2703 value = static_cast<uint32_t>(intValue);
2704 if (intValue < 0)
2705 {
2706 // Look for zero instead of one in value. This also handles the intValue ==
2707 // -1 special case, where the return value needs to be -1.
2708 value = ~value;
2709 }
2710 }
2711 else
2712 {
2713 ASSERT(getType().getBasicType() == EbtUInt);
2714 value = operandArray[i].getUConst();
2715 }
2716 resultArray[i].setIConst(gl::FindMSB(value));
2717 break;
2718 }
Olli Etuahof119a262016-08-19 15:54:22 +03002719 case EOpDFdx:
2720 case EOpDFdy:
2721 case EOpFwidth:
2722 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302723 // Derivatives of constant arguments should be 0.
2724 resultArray[i].setFConst(0.0f);
2725 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302726
Olli Etuahof119a262016-08-19 15:54:22 +03002727 default:
2728 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302729 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302730 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002731
Arun Patoleab2b9a22015-07-06 18:27:56 +05302732 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002733}
2734
Olli Etuahof119a262016-08-19 15:54:22 +03002735void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2736 FloatTypeUnaryFunc builtinFunc,
2737 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302738{
2739 ASSERT(builtinFunc);
2740
Olli Etuahof119a262016-08-19 15:54:22 +03002741 ASSERT(getType().getBasicType() == EbtFloat);
2742 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302743}
2744
Jamie Madillb1a85f42014-08-19 15:23:24 -04002745// static
Olli Etuahof119a262016-08-19 15:54:22 +03002746TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2747 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302748{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002749 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002750 TIntermSequence *arguments = aggregate->getSequence();
2751 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2752 std::vector<const TConstantUnion *> unionArrays(argsCount);
2753 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002754 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302755 TBasicType basicType = EbtVoid;
2756 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002757 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302758 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002759 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2760 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302761
2762 if (i == 0)
2763 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002764 basicType = argConstant->getType().getBasicType();
2765 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302766 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002767 unionArrays[i] = argConstant->getConstantValue();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002768 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002769 if (objectSizes[i] > maxObjectSize)
2770 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302771 }
2772
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002773 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302774 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002775 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302776 if (objectSizes[i] != maxObjectSize)
2777 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2778 }
Arun Patole274f0702015-05-05 13:33:30 +05302779
Olli Etuahob43846e2015-06-02 18:18:57 +03002780 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002781
2782 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302783 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002784 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302785 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002786 ASSERT(basicType == EbtFloat);
2787 resultArray = new TConstantUnion[maxObjectSize];
2788 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302789 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002790 float y = unionArrays[0][i].getFConst();
2791 float x = unionArrays[1][i].getFConst();
2792 // Results are undefined if x and y are both 0.
2793 if (x == 0.0f && y == 0.0f)
2794 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2795 else
2796 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302797 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002798 break;
2799 }
Arun Patolebf790422015-05-18 17:53:04 +05302800
Olli Etuaho51182ab2017-01-22 00:12:29 +00002801 case EOpPow:
2802 {
2803 ASSERT(basicType == EbtFloat);
2804 resultArray = new TConstantUnion[maxObjectSize];
2805 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302806 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002807 float x = unionArrays[0][i].getFConst();
2808 float y = unionArrays[1][i].getFConst();
2809 // Results are undefined if x < 0.
2810 // Results are undefined if x = 0 and y <= 0.
2811 if (x < 0.0f)
2812 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2813 else if (x == 0.0f && y <= 0.0f)
2814 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2815 else
2816 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302817 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002818 break;
2819 }
Arun Patolebf790422015-05-18 17:53:04 +05302820
Olli Etuaho51182ab2017-01-22 00:12:29 +00002821 case EOpMod:
2822 {
2823 ASSERT(basicType == EbtFloat);
2824 resultArray = new TConstantUnion[maxObjectSize];
2825 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302826 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002827 float x = unionArrays[0][i].getFConst();
2828 float y = unionArrays[1][i].getFConst();
2829 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302830 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002831 break;
2832 }
Arun Patolebf790422015-05-18 17:53:04 +05302833
Olli Etuaho51182ab2017-01-22 00:12:29 +00002834 case EOpMin:
2835 {
2836 resultArray = new TConstantUnion[maxObjectSize];
2837 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302838 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002839 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302840 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002841 case EbtFloat:
2842 resultArray[i].setFConst(
2843 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2844 break;
2845 case EbtInt:
2846 resultArray[i].setIConst(
2847 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2848 break;
2849 case EbtUInt:
2850 resultArray[i].setUConst(
2851 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2852 break;
2853 default:
2854 UNREACHABLE();
2855 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302856 }
2857 }
2858 break;
Arun Patole274f0702015-05-05 13:33:30 +05302859 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002860
2861 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302862 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002863 resultArray = new TConstantUnion[maxObjectSize];
2864 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302865 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002866 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302867 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002868 case EbtFloat:
2869 resultArray[i].setFConst(
2870 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2871 break;
2872 case EbtInt:
2873 resultArray[i].setIConst(
2874 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2875 break;
2876 case EbtUInt:
2877 resultArray[i].setUConst(
2878 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2879 break;
2880 default:
2881 UNREACHABLE();
2882 break;
Arun Patole274f0702015-05-05 13:33:30 +05302883 }
2884 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002885 break;
Arun Patole274f0702015-05-05 13:33:30 +05302886 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002887
2888 case EOpStep:
2889 {
2890 ASSERT(basicType == EbtFloat);
2891 resultArray = new TConstantUnion[maxObjectSize];
2892 for (size_t i = 0; i < maxObjectSize; i++)
2893 resultArray[i].setFConst(
2894 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2895 break;
2896 }
2897
2898 case EOpLessThanComponentWise:
2899 {
2900 resultArray = new TConstantUnion[maxObjectSize];
2901 for (size_t i = 0; i < maxObjectSize; i++)
2902 {
2903 switch (basicType)
2904 {
2905 case EbtFloat:
2906 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2907 unionArrays[1][i].getFConst());
2908 break;
2909 case EbtInt:
2910 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2911 unionArrays[1][i].getIConst());
2912 break;
2913 case EbtUInt:
2914 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2915 unionArrays[1][i].getUConst());
2916 break;
2917 default:
2918 UNREACHABLE();
2919 break;
2920 }
2921 }
2922 break;
2923 }
2924
2925 case EOpLessThanEqualComponentWise:
2926 {
2927 resultArray = new TConstantUnion[maxObjectSize];
2928 for (size_t i = 0; i < maxObjectSize; i++)
2929 {
2930 switch (basicType)
2931 {
2932 case EbtFloat:
2933 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2934 unionArrays[1][i].getFConst());
2935 break;
2936 case EbtInt:
2937 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2938 unionArrays[1][i].getIConst());
2939 break;
2940 case EbtUInt:
2941 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2942 unionArrays[1][i].getUConst());
2943 break;
2944 default:
2945 UNREACHABLE();
2946 break;
2947 }
2948 }
2949 break;
2950 }
2951
2952 case EOpGreaterThanComponentWise:
2953 {
2954 resultArray = new TConstantUnion[maxObjectSize];
2955 for (size_t i = 0; i < maxObjectSize; i++)
2956 {
2957 switch (basicType)
2958 {
2959 case EbtFloat:
2960 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2961 unionArrays[1][i].getFConst());
2962 break;
2963 case EbtInt:
2964 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2965 unionArrays[1][i].getIConst());
2966 break;
2967 case EbtUInt:
2968 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2969 unionArrays[1][i].getUConst());
2970 break;
2971 default:
2972 UNREACHABLE();
2973 break;
2974 }
2975 }
2976 break;
2977 }
2978 case EOpGreaterThanEqualComponentWise:
2979 {
2980 resultArray = new TConstantUnion[maxObjectSize];
2981 for (size_t i = 0; i < maxObjectSize; i++)
2982 {
2983 switch (basicType)
2984 {
2985 case EbtFloat:
2986 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2987 unionArrays[1][i].getFConst());
2988 break;
2989 case EbtInt:
2990 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2991 unionArrays[1][i].getIConst());
2992 break;
2993 case EbtUInt:
2994 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2995 unionArrays[1][i].getUConst());
2996 break;
2997 default:
2998 UNREACHABLE();
2999 break;
3000 }
3001 }
3002 }
3003 break;
3004
3005 case EOpEqualComponentWise:
3006 {
3007 resultArray = new TConstantUnion[maxObjectSize];
3008 for (size_t i = 0; i < maxObjectSize; i++)
3009 {
3010 switch (basicType)
3011 {
3012 case EbtFloat:
3013 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
3014 unionArrays[1][i].getFConst());
3015 break;
3016 case EbtInt:
3017 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
3018 unionArrays[1][i].getIConst());
3019 break;
3020 case EbtUInt:
3021 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
3022 unionArrays[1][i].getUConst());
3023 break;
3024 case EbtBool:
3025 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
3026 unionArrays[1][i].getBConst());
3027 break;
3028 default:
3029 UNREACHABLE();
3030 break;
3031 }
3032 }
3033 break;
3034 }
3035
3036 case EOpNotEqualComponentWise:
3037 {
3038 resultArray = new TConstantUnion[maxObjectSize];
3039 for (size_t i = 0; i < maxObjectSize; i++)
3040 {
3041 switch (basicType)
3042 {
3043 case EbtFloat:
3044 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
3045 unionArrays[1][i].getFConst());
3046 break;
3047 case EbtInt:
3048 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3049 unionArrays[1][i].getIConst());
3050 break;
3051 case EbtUInt:
3052 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3053 unionArrays[1][i].getUConst());
3054 break;
3055 case EbtBool:
3056 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3057 unionArrays[1][i].getBConst());
3058 break;
3059 default:
3060 UNREACHABLE();
3061 break;
3062 }
3063 }
3064 break;
3065 }
3066
3067 case EOpDistance:
3068 {
3069 ASSERT(basicType == EbtFloat);
3070 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3071 resultArray = new TConstantUnion();
3072 for (size_t i = 0; i < maxObjectSize; i++)
3073 {
3074 float x = unionArrays[0][i].getFConst();
3075 float y = unionArrays[1][i].getFConst();
3076 distanceArray[i].setFConst(x - y);
3077 }
3078 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3079 break;
3080 }
3081
3082 case EOpDot:
3083 ASSERT(basicType == EbtFloat);
3084 resultArray = new TConstantUnion();
3085 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3086 break;
3087
3088 case EOpCross:
3089 {
3090 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3091 resultArray = new TConstantUnion[maxObjectSize];
3092 float x0 = unionArrays[0][0].getFConst();
3093 float x1 = unionArrays[0][1].getFConst();
3094 float x2 = unionArrays[0][2].getFConst();
3095 float y0 = unionArrays[1][0].getFConst();
3096 float y1 = unionArrays[1][1].getFConst();
3097 float y2 = unionArrays[1][2].getFConst();
3098 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3099 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3100 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3101 break;
3102 }
3103
3104 case EOpReflect:
3105 {
3106 ASSERT(basicType == EbtFloat);
3107 // genType reflect (genType I, genType N) :
3108 // For the incident vector I and surface orientation N, returns the reflection
3109 // direction:
3110 // I - 2 * dot(N, I) * N.
3111 resultArray = new TConstantUnion[maxObjectSize];
3112 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3113 for (size_t i = 0; i < maxObjectSize; i++)
3114 {
3115 float result = unionArrays[0][i].getFConst() -
3116 2.0f * dotProduct * unionArrays[1][i].getFConst();
3117 resultArray[i].setFConst(result);
3118 }
3119 break;
3120 }
3121
3122 case EOpMulMatrixComponentWise:
3123 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003124 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3125 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003126 // Perform component-wise matrix multiplication.
3127 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003128 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003129 angle::Matrix<float> result =
3130 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3131 SetUnionArrayFromMatrix(result, resultArray);
3132 break;
3133 }
3134
3135 case EOpOuterProduct:
3136 {
3137 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003138 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3139 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003140 resultArray = new TConstantUnion[numRows * numCols];
3141 angle::Matrix<float> result =
3142 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3143 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3144 SetUnionArrayFromMatrix(result, resultArray);
3145 break;
3146 }
3147
3148 case EOpClamp:
3149 {
3150 resultArray = new TConstantUnion[maxObjectSize];
3151 for (size_t i = 0; i < maxObjectSize; i++)
3152 {
3153 switch (basicType)
3154 {
3155 case EbtFloat:
3156 {
3157 float x = unionArrays[0][i].getFConst();
3158 float min = unionArrays[1][i].getFConst();
3159 float max = unionArrays[2][i].getFConst();
3160 // Results are undefined if min > max.
3161 if (min > max)
3162 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3163 &resultArray[i]);
3164 else
3165 resultArray[i].setFConst(gl::clamp(x, min, max));
3166 break;
3167 }
3168
3169 case EbtInt:
3170 {
3171 int x = unionArrays[0][i].getIConst();
3172 int min = unionArrays[1][i].getIConst();
3173 int max = unionArrays[2][i].getIConst();
3174 // Results are undefined if min > max.
3175 if (min > max)
3176 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3177 &resultArray[i]);
3178 else
3179 resultArray[i].setIConst(gl::clamp(x, min, max));
3180 break;
3181 }
3182 case EbtUInt:
3183 {
3184 unsigned int x = unionArrays[0][i].getUConst();
3185 unsigned int min = unionArrays[1][i].getUConst();
3186 unsigned int max = unionArrays[2][i].getUConst();
3187 // Results are undefined if min > max.
3188 if (min > max)
3189 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3190 &resultArray[i]);
3191 else
3192 resultArray[i].setUConst(gl::clamp(x, min, max));
3193 break;
3194 }
3195 default:
3196 UNREACHABLE();
3197 break;
3198 }
3199 }
3200 break;
3201 }
3202
3203 case EOpMix:
3204 {
3205 ASSERT(basicType == EbtFloat);
3206 resultArray = new TConstantUnion[maxObjectSize];
3207 for (size_t i = 0; i < maxObjectSize; i++)
3208 {
3209 float x = unionArrays[0][i].getFConst();
3210 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003211 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003212 if (type == EbtFloat)
3213 {
3214 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3215 float a = unionArrays[2][i].getFConst();
3216 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3217 }
3218 else // 3rd parameter is EbtBool
3219 {
3220 ASSERT(type == EbtBool);
3221 // Selects which vector each returned component comes from.
3222 // For a component of a that is false, the corresponding component of x is
3223 // returned.
3224 // For a component of a that is true, the corresponding component of y is
3225 // returned.
3226 bool a = unionArrays[2][i].getBConst();
3227 resultArray[i].setFConst(a ? y : x);
3228 }
3229 }
3230 break;
3231 }
3232
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02003233 case EOpSmoothstep:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003234 {
3235 ASSERT(basicType == EbtFloat);
3236 resultArray = new TConstantUnion[maxObjectSize];
3237 for (size_t i = 0; i < maxObjectSize; i++)
3238 {
3239 float edge0 = unionArrays[0][i].getFConst();
3240 float edge1 = unionArrays[1][i].getFConst();
3241 float x = unionArrays[2][i].getFConst();
3242 // Results are undefined if edge0 >= edge1.
3243 if (edge0 >= edge1)
3244 {
3245 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3246 }
3247 else
3248 {
3249 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3250 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3251 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3252 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3253 }
3254 }
3255 break;
3256 }
3257
Olli Etuaho74da73f2017-02-01 15:37:48 +00003258 case EOpLdexp:
3259 {
3260 resultArray = new TConstantUnion[maxObjectSize];
3261 for (size_t i = 0; i < maxObjectSize; i++)
3262 {
3263 float x = unionArrays[0][i].getFConst();
3264 int exp = unionArrays[1][i].getIConst();
3265 if (exp > 128)
3266 {
3267 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3268 }
3269 else
3270 {
3271 resultArray[i].setFConst(gl::Ldexp(x, exp));
3272 }
3273 }
3274 break;
3275 }
3276
Jamie Madille72595b2017-06-06 15:12:26 -04003277 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003278 {
3279 ASSERT(basicType == EbtFloat);
3280 // genType faceforward(genType N, genType I, genType Nref) :
3281 // If dot(Nref, I) < 0 return N, otherwise return -N.
3282 resultArray = new TConstantUnion[maxObjectSize];
3283 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3284 for (size_t i = 0; i < maxObjectSize; i++)
3285 {
3286 if (dotProduct < 0)
3287 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3288 else
3289 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3290 }
3291 break;
3292 }
3293
3294 case EOpRefract:
3295 {
3296 ASSERT(basicType == EbtFloat);
3297 // genType refract(genType I, genType N, float eta) :
3298 // For the incident vector I and surface normal N, and the ratio of indices of
3299 // refraction eta,
3300 // return the refraction vector. The result is computed by
3301 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3302 // if (k < 0.0)
3303 // return genType(0.0)
3304 // else
3305 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3306 resultArray = new TConstantUnion[maxObjectSize];
3307 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3308 for (size_t i = 0; i < maxObjectSize; i++)
3309 {
3310 float eta = unionArrays[2][i].getFConst();
3311 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3312 if (k < 0.0f)
3313 resultArray[i].setFConst(0.0f);
3314 else
3315 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3316 (eta * dotProduct + sqrtf(k)) *
3317 unionArrays[1][i].getFConst());
3318 }
3319 break;
3320 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003321 case EOpBitfieldExtract:
3322 {
3323 resultArray = new TConstantUnion[maxObjectSize];
3324 for (size_t i = 0; i < maxObjectSize; ++i)
3325 {
3326 int offset = unionArrays[1][0].getIConst();
3327 int bits = unionArrays[2][0].getIConst();
3328 if (bits == 0)
3329 {
3330 if (aggregate->getBasicType() == EbtInt)
3331 {
3332 resultArray[i].setIConst(0);
3333 }
3334 else
3335 {
3336 ASSERT(aggregate->getBasicType() == EbtUInt);
3337 resultArray[i].setUConst(0);
3338 }
3339 }
3340 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3341 {
3342 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3343 &resultArray[i]);
3344 }
3345 else
3346 {
3347 // bits can be 32 here, so we need to avoid bit shift overflow.
3348 uint32_t maskMsb = 1u << (bits - 1);
3349 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3350 if (aggregate->getBasicType() == EbtInt)
3351 {
3352 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3353 uint32_t resultUnsigned = (value & mask) >> offset;
3354 if ((resultUnsigned & maskMsb) != 0)
3355 {
3356 // The most significant bits (from bits+1 to the most significant bit)
3357 // should be set to 1.
3358 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3359 resultUnsigned |= higherBitsMask;
3360 }
3361 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3362 }
3363 else
3364 {
3365 ASSERT(aggregate->getBasicType() == EbtUInt);
3366 uint32_t value = unionArrays[0][i].getUConst();
3367 resultArray[i].setUConst((value & mask) >> offset);
3368 }
3369 }
3370 }
3371 break;
3372 }
3373 case EOpBitfieldInsert:
3374 {
3375 resultArray = new TConstantUnion[maxObjectSize];
3376 for (size_t i = 0; i < maxObjectSize; ++i)
3377 {
3378 int offset = unionArrays[2][0].getIConst();
3379 int bits = unionArrays[3][0].getIConst();
3380 if (bits == 0)
3381 {
3382 if (aggregate->getBasicType() == EbtInt)
3383 {
3384 int32_t base = unionArrays[0][i].getIConst();
3385 resultArray[i].setIConst(base);
3386 }
3387 else
3388 {
3389 ASSERT(aggregate->getBasicType() == EbtUInt);
3390 uint32_t base = unionArrays[0][i].getUConst();
3391 resultArray[i].setUConst(base);
3392 }
3393 }
3394 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3395 {
3396 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3397 &resultArray[i]);
3398 }
3399 else
3400 {
3401 // bits can be 32 here, so we need to avoid bit shift overflow.
3402 uint32_t maskMsb = 1u << (bits - 1);
3403 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3404 uint32_t baseMask = ~insertMask;
3405 if (aggregate->getBasicType() == EbtInt)
3406 {
3407 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3408 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3409 uint32_t resultUnsigned =
3410 (base & baseMask) | ((insert << offset) & insertMask);
3411 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3412 }
3413 else
3414 {
3415 ASSERT(aggregate->getBasicType() == EbtUInt);
3416 uint32_t base = unionArrays[0][i].getUConst();
3417 uint32_t insert = unionArrays[1][i].getUConst();
3418 resultArray[i].setUConst((base & baseMask) |
3419 ((insert << offset) & insertMask));
3420 }
3421 }
3422 }
3423 break;
3424 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003425
3426 default:
3427 UNREACHABLE();
3428 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303429 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003430 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303431}
3432
Jamie Madill45bcc782016-11-07 13:58:48 -05003433} // namespace sh