blob: 1004f2767c0dd7b10d15cd3a5f6899b022dc6401 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Olli Etuahofbb1c792018-01-19 16:26:59 +020021#include "compiler/translator/ImmutableString.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040022#include "compiler/translator/IntermNode.h"
23#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040024#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040025
Jamie Madill45bcc782016-11-07 13:58:48 -050026namespace sh
27{
28
Jamie Madillb1a85f42014-08-19 15:23:24 -040029namespace
30{
31
Jamie Madilld7b1ab52016-12-12 14:42:19 -050032const float kPi = 3.14159265358979323846f;
Arun Patole9dea48f2015-04-02 11:45:09 +053033const float kDegreesToRadiansMultiplier = kPi / 180.0f;
34const float kRadiansToDegreesMultiplier = 180.0f / kPi;
35
Jamie Madillb1a85f42014-08-19 15:23:24 -040036TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
37{
38 return left > right ? left : right;
39}
40
Arun Patole274f0702015-05-05 13:33:30 +053041TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
42{
43 TConstantUnion *constUnion = new TConstantUnion[size];
44 for (unsigned int i = 0; i < size; ++i)
Jamie Madilld7b1ab52016-12-12 14:42:19 -050045 constUnion[i] = constant;
Arun Patole274f0702015-05-05 13:33:30 +053046
47 return constUnion;
48}
49
Olli Etuahof119a262016-08-19 15:54:22 +030050void UndefinedConstantFoldingError(const TSourceLoc &loc,
51 TOperator op,
52 TBasicType basicType,
53 TDiagnostics *diagnostics,
54 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053055{
Olli Etuahof119a262016-08-19 15:54:22 +030056 diagnostics->warning(loc, "operation result is undefined for the values passed in",
Olli Etuaho4de340a2016-12-16 09:32:03 +000057 GetOperatorString(op));
Arun Patolebf790422015-05-18 17:53:04 +053058
59 switch (basicType)
60 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050061 case EbtFloat:
62 result->setFConst(0.0f);
63 break;
64 case EbtInt:
65 result->setIConst(0);
66 break;
67 case EbtUInt:
68 result->setUConst(0u);
69 break;
70 case EbtBool:
71 result->setBConst(false);
72 break;
73 default:
74 break;
Arun Patolebf790422015-05-18 17:53:04 +053075 }
76}
77
Olli Etuaho5c0e0232015-11-11 15:55:59 +020078float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053079{
80 float result = 0.0f;
81 for (size_t i = 0; i < paramArraySize; i++)
82 {
83 float f = paramArray[i].getFConst();
84 result += f * f;
85 }
86 return sqrtf(result);
87}
88
Olli Etuaho5c0e0232015-11-11 15:55:59 +020089float VectorDotProduct(const TConstantUnion *paramArray1,
90 const TConstantUnion *paramArray2,
91 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053092{
93 float result = 0.0f;
94 for (size_t i = 0; i < paramArraySize; i++)
95 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
96 return result;
97}
98
Olli Etuaho2768bc82017-12-12 11:51:48 +020099TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray, const TIntermTyped *originalNode)
Olli Etuahob43846e2015-06-02 18:18:57 +0300100{
Olli Etuaho2768bc82017-12-12 11:51:48 +0200101 ASSERT(constArray != nullptr);
102 // Note that we inherit whatever qualifier the folded node had. Nodes may be constant folded
103 // without being qualified as constant.
Olli Etuahob43846e2015-06-02 18:18:57 +0300104 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuahob43846e2015-06-02 18:18:57 +0300105 folded->setLine(originalNode->getLine());
106 return folded;
107}
108
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200109angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
110 const unsigned int &rows,
111 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530112{
113 std::vector<float> elements;
114 for (size_t i = 0; i < rows * cols; i++)
115 elements.push_back(paramArray[i].getFConst());
116 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300117 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
118 // so that the created matrix will have the expected dimensions after the transpose.
119 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530120}
121
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200122angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530123{
124 std::vector<float> elements;
125 for (size_t i = 0; i < size * size; i++)
126 elements.push_back(paramArray[i].getFConst());
127 // Transpose is used since the Matrix constructor expects arguments in row-major order,
128 // whereas the paramArray is in column-major order.
129 return angle::Matrix<float>(elements, size).transpose();
130}
131
132void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
133{
134 // Transpose is used since the input Matrix is in row-major order,
135 // whereas the actual result should be in column-major order.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500136 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530137 std::vector<float> resultElements = result.elements();
138 for (size_t i = 0; i < resultElements.size(); i++)
139 resultArray[i].setFConst(resultElements[i]);
140}
141
Olli Etuaho765924f2018-01-04 12:48:36 +0200142bool CanFoldAggregateBuiltInOp(TOperator op)
143{
144 switch (op)
145 {
146 case EOpAtan:
147 case EOpPow:
148 case EOpMod:
149 case EOpMin:
150 case EOpMax:
151 case EOpClamp:
152 case EOpMix:
153 case EOpStep:
Olli Etuahof7f0b8c2018-02-21 20:02:23 +0200154 case EOpSmoothstep:
Olli Etuaho765924f2018-01-04 12:48:36 +0200155 case EOpLdexp:
156 case EOpMulMatrixComponentWise:
157 case EOpOuterProduct:
158 case EOpEqualComponentWise:
159 case EOpNotEqualComponentWise:
160 case EOpLessThanComponentWise:
161 case EOpLessThanEqualComponentWise:
162 case EOpGreaterThanComponentWise:
163 case EOpGreaterThanEqualComponentWise:
164 case EOpDistance:
165 case EOpDot:
166 case EOpCross:
167 case EOpFaceforward:
168 case EOpReflect:
169 case EOpRefract:
170 case EOpBitfieldExtract:
171 case EOpBitfieldInsert:
172 return true;
173 default:
174 return false;
175 }
176}
177
Jamie Madillb1a85f42014-08-19 15:23:24 -0400178} // namespace anonymous
179
Jamie Madillb1a85f42014-08-19 15:23:24 -0400180////////////////////////////////////////////////////////////////
181//
182// Member functions of the nodes used for building the tree.
183//
184////////////////////////////////////////////////////////////////
185
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200186TIntermExpression::TIntermExpression(const TType &t) : TIntermTyped(), mType(t)
187{
188}
189
190void TIntermExpression::setTypePreservePrecision(const TType &t)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300191{
192 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500193 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300194 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
195 mType.setPrecision(precision);
196}
197
Jamie Madillb1a85f42014-08-19 15:23:24 -0400198#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500199 if (node == original) \
200 { \
201 node = static_cast<type *>(replacement); \
202 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400203 }
204
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500205bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400206{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300207 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400208 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
209 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
210 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100211 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400212 return false;
213}
214
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500215bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400216{
217 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
218 return false;
219}
220
Olli Etuahob6fa0432016-09-28 16:28:05 +0100221bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
222{
223 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
224 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
225 return false;
226}
227
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500228bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400229{
230 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
231 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
232 return false;
233}
234
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500235bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400236{
Olli Etuahoa2234302016-08-31 12:05:39 +0300237 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400238 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
239 return false;
240}
241
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000242bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
243{
244 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
245 return false;
246}
247
Olli Etuaho336b1472016-10-05 16:37:55 +0100248bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
249{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000250 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100251 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
252 return false;
253}
254
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500255bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400256{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100257 return replaceChildNodeInternal(original, replacement);
258}
259
260bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
261{
262 return replaceChildNodeInternal(original, replacement);
263}
264
Olli Etuaho16c745a2017-01-16 17:02:27 +0000265bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
266{
Olli Etuahod4bd9632018-03-08 16:32:44 +0200267 return false;
Olli Etuaho16c745a2017-01-16 17:02:27 +0000268}
269
Olli Etuaho13389b62016-10-16 11:48:18 +0100270bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
271{
272 return replaceChildNodeInternal(original, replacement);
273}
274
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100275bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
276{
277 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400278 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100279 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400280 }
281 return false;
282}
283
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100284bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
285 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300286{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100287 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300288 {
289 if (*it == original)
290 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100291 it = getSequence()->erase(it);
292 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300293 return true;
294 }
295 }
296 return false;
297}
298
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100299bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
300 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300301{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100302 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300303 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300304 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300305 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100306 auto it = getSequence()->begin() + position;
307 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300308 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300309}
310
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200311TIntermSymbol::TIntermSymbol(const TVariable *variable) : TIntermTyped(), mVariable(variable)
Olli Etuaho195be942017-12-04 23:40:14 +0200312{
Olli Etuaho195be942017-12-04 23:40:14 +0200313}
314
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200315bool TIntermSymbol::hasConstantValue() const
316{
317 return variable().getConstPointer() != nullptr;
318}
319
320const TConstantUnion *TIntermSymbol::getConstantValue() const
321{
322 return variable().getConstPointer();
323}
324
Olli Etuahob6af22b2017-12-15 14:05:44 +0200325const TSymbolUniqueId &TIntermSymbol::uniqueId() const
326{
327 return mVariable->uniqueId();
328}
329
Olli Etuahofbb1c792018-01-19 16:26:59 +0200330ImmutableString TIntermSymbol::getName() const
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200331{
332 return mVariable->name();
333}
334
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200335const TType &TIntermSymbol::getType() const
336{
337 return mVariable->getType();
338}
339
Olli Etuahofe486322017-03-21 09:30:54 +0000340TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
341 TIntermSequence *arguments)
342{
Olli Etuaho0c371002017-12-13 17:00:25 +0400343 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000344}
345
Olli Etuaho0c371002017-12-13 17:00:25 +0400346TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
347 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000348{
Olli Etuaho0c371002017-12-13 17:00:25 +0400349 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000350}
351
352TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
353 TIntermSequence *arguments)
354{
Olli Etuahoe80825e2018-02-16 10:24:53 +0200355 // op should be either EOpCallBuiltInFunction or a specific math op.
356 ASSERT(func.getBuiltInOp() != EOpNull);
357 return new TIntermAggregate(&func, func.getReturnType(), func.getBuiltInOp(), arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000358}
359
360TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000361 TIntermSequence *arguments)
362{
Olli Etuaho0c371002017-12-13 17:00:25 +0400363 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000364}
365
Olli Etuaho0c371002017-12-13 17:00:25 +0400366TIntermAggregate::TIntermAggregate(const TFunction *func,
367 const TType &type,
368 TOperator op,
369 TIntermSequence *arguments)
Olli Etuahoe80825e2018-02-16 10:24:53 +0200370 : TIntermOperator(op, type),
Olli Etuaho0c371002017-12-13 17:00:25 +0400371 mUseEmulatedFunction(false),
372 mGotPrecisionFromChildren(false),
373 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800374{
375 if (arguments != nullptr)
376 {
377 mArguments.swap(*arguments);
378 }
Olli Etuaho1bb85282017-12-14 13:39:53 +0200379 ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
Olli Etuahoe80825e2018-02-16 10:24:53 +0200380 setPrecisionAndQualifier();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800381}
382
Olli Etuahoe80825e2018-02-16 10:24:53 +0200383void TIntermAggregate::setPrecisionAndQualifier()
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800384{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800385 mType.setQualifier(EvqTemporary);
Olli Etuahoe80825e2018-02-16 10:24:53 +0200386 if (mOp == EOpCallBuiltInFunction)
387 {
388 setBuiltInFunctionPrecision();
389 }
390 else if (!isFunctionCall())
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800391 {
392 if (isConstructor())
393 {
394 // Structs should not be precision qualified, the individual members may be.
395 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300396 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800397 {
398 setPrecisionFromChildren();
399 }
400 }
401 else
402 {
403 setPrecisionForBuiltInOp();
404 }
405 if (areChildrenConstQualified())
406 {
407 mType.setQualifier(EvqConst);
408 }
409 }
410}
411
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200412bool TIntermAggregate::areChildrenConstQualified()
413{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800414 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200415 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800416 TIntermTyped *typedArg = arg->getAsTyped();
417 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200418 {
419 return false;
420 }
421 }
422 return true;
423}
424
Olli Etuahod2a67b92014-10-21 16:42:57 +0300425void TIntermAggregate::setPrecisionFromChildren()
426{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300427 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300428 if (getBasicType() == EbtBool)
429 {
430 mType.setPrecision(EbpUndefined);
431 return;
432 }
433
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500434 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800435 TIntermSequence::iterator childIter = mArguments.begin();
436 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300437 {
438 TIntermTyped *typed = (*childIter)->getAsTyped();
439 if (typed)
440 precision = GetHigherPrecision(typed->getPrecision(), precision);
441 ++childIter;
442 }
443 mType.setPrecision(precision);
444}
445
Olli Etuaho9250cb22017-01-21 10:51:27 +0000446void TIntermAggregate::setPrecisionForBuiltInOp()
447{
448 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800449 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000450 if (!setPrecisionForSpecialBuiltInOp())
451 {
452 setPrecisionFromChildren();
453 }
454}
455
456bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
457{
458 switch (mOp)
459 {
460 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800461 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
462 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000463 return true;
464 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800465 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
466 mArguments[1]->getAsTyped()->getPrecision()));
467 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000468 return true;
469 case EOpUaddCarry:
470 case EOpUsubBorrow:
471 mType.setPrecision(EbpHigh);
472 return true;
473 default:
474 return false;
475 }
476}
477
Olli Etuahod2a67b92014-10-21 16:42:57 +0300478void TIntermAggregate::setBuiltInFunctionPrecision()
479{
480 // All built-ins returning bool should be handled as ops, not functions.
481 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800482 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300483
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800484 TPrecision precision = EbpUndefined;
485 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300486 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800487 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300488 // ESSL spec section 8: texture functions get their precision from the sampler.
489 if (typed && IsSampler(typed->getBasicType()))
490 {
491 precision = typed->getPrecision();
492 break;
493 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300494 }
495 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
496 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahofbb1c792018-01-19 16:26:59 +0200497 if (mFunction->name() == "textureSize")
Olli Etuahod2a67b92014-10-21 16:42:57 +0300498 mType.setPrecision(EbpHigh);
499 else
500 mType.setPrecision(precision);
501}
502
Olli Etuaho0c371002017-12-13 17:00:25 +0400503const char *TIntermAggregate::functionName() const
504{
505 ASSERT(!isConstructor());
506 switch (mOp)
507 {
508 case EOpCallInternalRawFunction:
509 case EOpCallBuiltInFunction:
510 case EOpCallFunctionInAST:
Olli Etuahofbb1c792018-01-19 16:26:59 +0200511 return mFunction->name().data();
Olli Etuaho0c371002017-12-13 17:00:25 +0400512 default:
513 return GetOperatorString(mOp);
514 }
515}
516
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200517bool TIntermAggregate::hasConstantValue() const
518{
519 if (!isConstructor())
520 {
521 return false;
522 }
523 for (TIntermNode *constructorArg : mArguments)
524 {
525 if (!constructorArg->getAsTyped()->hasConstantValue())
526 {
527 return false;
528 }
529 }
530 return true;
531}
532
533const TConstantUnion *TIntermAggregate::getConstantValue() const
534{
535 if (!hasConstantValue())
536 {
537 return nullptr;
538 }
539 ASSERT(isConstructor());
540 ASSERT(mArguments.size() > 0u);
541
542 TConstantUnion *constArray = nullptr;
543 if (isArray())
544 {
545 size_t elementSize = mArguments.front()->getAsTyped()->getType().getObjectSize();
546 constArray = new TConstantUnion[elementSize * getOutermostArraySize()];
547
548 size_t elementOffset = 0u;
549 for (TIntermNode *constructorArg : mArguments)
550 {
551 const TConstantUnion *elementConstArray =
552 constructorArg->getAsTyped()->getConstantValue();
553 ASSERT(elementConstArray);
554 size_t elementSizeBytes = sizeof(TConstantUnion) * elementSize;
555 memcpy(static_cast<void *>(&constArray[elementOffset]),
556 static_cast<const void *>(elementConstArray), elementSizeBytes);
557 elementOffset += elementSize;
558 }
559 return constArray;
560 }
561
562 size_t resultSize = getType().getObjectSize();
563 constArray = new TConstantUnion[resultSize];
564 TBasicType basicType = getBasicType();
565
566 size_t resultIndex = 0u;
567
568 if (mArguments.size() == 1u)
569 {
570 TIntermNode *argument = mArguments.front();
571 TIntermTyped *argumentTyped = argument->getAsTyped();
572 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
573 // Check the special case of constructing a matrix diagonal from a single scalar,
574 // or a vector from a single scalar.
575 if (argumentTyped->getType().getObjectSize() == 1u)
576 {
577 if (isMatrix())
578 {
579 int resultCols = getType().getCols();
580 int resultRows = getType().getRows();
581 for (int col = 0; col < resultCols; ++col)
582 {
583 for (int row = 0; row < resultRows; ++row)
584 {
585 if (col == row)
586 {
587 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
588 }
589 else
590 {
591 constArray[resultIndex].setFConst(0.0f);
592 }
593 ++resultIndex;
594 }
595 }
596 }
597 else
598 {
599 while (resultIndex < resultSize)
600 {
601 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
602 ++resultIndex;
603 }
604 }
605 ASSERT(resultIndex == resultSize);
606 return constArray;
607 }
608 else if (isMatrix() && argumentTyped->isMatrix())
609 {
610 // The special case of constructing a matrix from a matrix.
611 int argumentCols = argumentTyped->getType().getCols();
612 int argumentRows = argumentTyped->getType().getRows();
613 int resultCols = getType().getCols();
614 int resultRows = getType().getRows();
615 for (int col = 0; col < resultCols; ++col)
616 {
617 for (int row = 0; row < resultRows; ++row)
618 {
619 if (col < argumentCols && row < argumentRows)
620 {
621 constArray[resultIndex].cast(
622 basicType, argumentConstantValue[col * argumentRows + row]);
623 }
624 else if (col == row)
625 {
626 constArray[resultIndex].setFConst(1.0f);
627 }
628 else
629 {
630 constArray[resultIndex].setFConst(0.0f);
631 }
632 ++resultIndex;
633 }
634 }
635 ASSERT(resultIndex == resultSize);
636 return constArray;
637 }
638 }
639
640 for (TIntermNode *argument : mArguments)
641 {
642 TIntermTyped *argumentTyped = argument->getAsTyped();
643 size_t argumentSize = argumentTyped->getType().getObjectSize();
644 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
645 for (size_t i = 0u; i < argumentSize; ++i)
646 {
647 if (resultIndex >= resultSize)
648 break;
649 constArray[resultIndex].cast(basicType, argumentConstantValue[i]);
650 ++resultIndex;
651 }
652 }
653 ASSERT(resultIndex == resultSize);
654 return constArray;
655}
656
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300657bool TIntermAggregate::hasSideEffects() const
658{
Olli Etuahoea78d2b2018-01-09 12:55:27 +0200659 if (getQualifier() == EvqConst)
660 {
661 return false;
662 }
663 bool calledFunctionHasNoSideEffects =
664 isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects();
665 if (calledFunctionHasNoSideEffects || isConstructor())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300666 {
667 for (TIntermNode *arg : mArguments)
668 {
669 if (arg->getAsTyped()->hasSideEffects())
670 {
671 return true;
672 }
673 }
674 return false;
675 }
676 // Conservatively assume most aggregate operators have side-effects
677 return true;
678}
679
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100680void TIntermBlock::appendStatement(TIntermNode *statement)
681{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300682 // Declaration nodes with no children can appear if it was an empty declaration or if all the
683 // declarators just added constants to the symbol table instead of generating code. We still
684 // need to add the declaration to the AST in that case because it might be relevant to the
685 // validity of switch/case.
686 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100687 {
688 mStatements.push_back(statement);
689 }
690}
691
Olli Etuaho13389b62016-10-16 11:48:18 +0100692void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
693{
694 ASSERT(declarator != nullptr);
695 ASSERT(declarator->getAsSymbolNode() != nullptr ||
696 (declarator->getAsBinaryNode() != nullptr &&
697 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
698 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300699 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100700 mDeclarators.push_back(declarator);
701}
702
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300703bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
704{
705 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
706 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
707 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
708 return false;
709}
710
Olli Etuaho57961272016-09-14 13:57:46 +0300711bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400712{
713 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100714 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
715 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400716 return false;
717}
718
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500719bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200720{
721 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100722 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300723 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200724 return false;
725}
726
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500727bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200728{
729 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
730 return false;
731}
732
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200733TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode()
Olli Etuahod7a25242015-08-18 13:49:45 +0300734{
735 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
736 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200737 // We need to manually copy any fields of TIntermNode.
Olli Etuahod7a25242015-08-18 13:49:45 +0300738 mLine = node.mLine;
739}
740
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200741bool TIntermTyped::hasConstantValue() const
Olli Etuahod4f4c112016-04-15 15:11:24 +0300742{
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200743 return false;
744}
745
746const TConstantUnion *TIntermTyped::getConstantValue() const
747{
748 return nullptr;
Olli Etuahod4f4c112016-04-15 15:11:24 +0300749}
750
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200751TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node)
752 : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300753{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200754 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300755}
756
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200757TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200758 : TIntermTyped(), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100759{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200760 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100761}
762
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200763const TType &TIntermFunctionPrototype::getType() const
764{
765 return mFunction->getReturnType();
766}
767
Olli Etuahod7a25242015-08-18 13:49:45 +0300768TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
769 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300770 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100771 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400772 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300773{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800774 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300775 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800776 TIntermTyped *typedArg = arg->getAsTyped();
777 ASSERT(typedArg != nullptr);
778 TIntermTyped *argCopy = typedArg->deepCopy();
779 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300780 }
781}
782
Olli Etuahofe486322017-03-21 09:30:54 +0000783TIntermAggregate *TIntermAggregate::shallowCopy() const
784{
785 TIntermSequence *copySeq = new TIntermSequence();
786 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400787 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000788 copyNode->setLine(mLine);
789 return copyNode;
790}
791
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200792TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermExpression(node)
Olli Etuahob6fa0432016-09-28 16:28:05 +0100793{
794 TIntermTyped *operandCopy = node.mOperand->deepCopy();
795 ASSERT(operandCopy != nullptr);
796 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000797 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100798}
799
Olli Etuahod7a25242015-08-18 13:49:45 +0300800TIntermBinary::TIntermBinary(const TIntermBinary &node)
801 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
802{
803 TIntermTyped *leftCopy = node.mLeft->deepCopy();
804 TIntermTyped *rightCopy = node.mRight->deepCopy();
805 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
806 mLeft = leftCopy;
807 mRight = rightCopy;
808}
809
810TIntermUnary::TIntermUnary(const TIntermUnary &node)
811 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
812{
813 TIntermTyped *operandCopy = node.mOperand->deepCopy();
814 ASSERT(operandCopy != nullptr);
815 mOperand = operandCopy;
816}
817
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200818TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300819{
Olli Etuahod7a25242015-08-18 13:49:45 +0300820 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300821 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
822 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300823 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300824 mCondition = conditionCopy;
825 mTrueExpression = trueCopy;
826 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300827}
828
Jamie Madillb1a85f42014-08-19 15:23:24 -0400829bool TIntermOperator::isAssignment() const
830{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300831 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400832}
833
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300834bool TIntermOperator::isMultiplication() const
835{
836 switch (mOp)
837 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500838 case EOpMul:
839 case EOpMatrixTimesMatrix:
840 case EOpMatrixTimesVector:
841 case EOpMatrixTimesScalar:
842 case EOpVectorTimesMatrix:
843 case EOpVectorTimesScalar:
844 return true;
845 default:
846 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300847 }
848}
849
Jamie Madillb1a85f42014-08-19 15:23:24 -0400850bool TIntermOperator::isConstructor() const
851{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300852 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400853}
854
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800855bool TIntermOperator::isFunctionCall() const
856{
857 switch (mOp)
858 {
859 case EOpCallFunctionInAST:
860 case EOpCallBuiltInFunction:
861 case EOpCallInternalRawFunction:
862 return true;
863 default:
864 return false;
865 }
866}
867
Olli Etuaho1dded802016-08-18 18:13:13 +0300868TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
869{
870 if (left.isMatrix())
871 {
872 if (right.isMatrix())
873 {
874 return EOpMatrixTimesMatrix;
875 }
876 else
877 {
878 if (right.isVector())
879 {
880 return EOpMatrixTimesVector;
881 }
882 else
883 {
884 return EOpMatrixTimesScalar;
885 }
886 }
887 }
888 else
889 {
890 if (right.isMatrix())
891 {
892 if (left.isVector())
893 {
894 return EOpVectorTimesMatrix;
895 }
896 else
897 {
898 return EOpMatrixTimesScalar;
899 }
900 }
901 else
902 {
903 // Neither operand is a matrix.
904 if (left.isVector() == right.isVector())
905 {
906 // Leave as component product.
907 return EOpMul;
908 }
909 else
910 {
911 return EOpVectorTimesScalar;
912 }
913 }
914 }
915}
916
917TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
918{
919 if (left.isMatrix())
920 {
921 if (right.isMatrix())
922 {
923 return EOpMatrixTimesMatrixAssign;
924 }
925 else
926 {
927 // right should be scalar, but this may not be validated yet.
928 return EOpMatrixTimesScalarAssign;
929 }
930 }
931 else
932 {
933 if (right.isMatrix())
934 {
935 // Left should be a vector, but this may not be validated yet.
936 return EOpVectorTimesMatrixAssign;
937 }
938 else
939 {
940 // Neither operand is a matrix.
941 if (left.isVector() == right.isVector())
942 {
943 // Leave as component product.
944 return EOpMulAssign;
945 }
946 else
947 {
948 // left should be vector and right should be scalar, but this may not be validated
949 // yet.
950 return EOpVectorTimesScalarAssign;
951 }
952 }
953 }
954}
955
Jamie Madillb1a85f42014-08-19 15:23:24 -0400956//
957// Make sure the type of a unary operator is appropriate for its
958// combination of operation and operand type.
959//
Olli Etuahoa2234302016-08-31 12:05:39 +0300960void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400961{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300962 if (mOp == EOpArrayLength)
963 {
964 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
965 setType(TType(EbtInt, EbpUndefined, EvqConst));
966 return;
967 }
968
Olli Etuahoa2234302016-08-31 12:05:39 +0300969 TQualifier resultQualifier = EvqTemporary;
970 if (mOperand->getQualifier() == EvqConst)
971 resultQualifier = EvqConst;
972
973 unsigned char operandPrimarySize =
974 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400975 switch (mOp)
976 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300977 case EOpFloatBitsToInt:
978 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
979 break;
980 case EOpFloatBitsToUint:
981 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
982 break;
983 case EOpIntBitsToFloat:
984 case EOpUintBitsToFloat:
985 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
986 break;
987 case EOpPackSnorm2x16:
988 case EOpPackUnorm2x16:
989 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800990 case EOpPackUnorm4x8:
991 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300992 setType(TType(EbtUInt, EbpHigh, resultQualifier));
993 break;
994 case EOpUnpackSnorm2x16:
995 case EOpUnpackUnorm2x16:
996 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
997 break;
998 case EOpUnpackHalf2x16:
999 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
1000 break;
Olli Etuaho25aef452017-01-29 16:15:44 -08001001 case EOpUnpackUnorm4x8:
1002 case EOpUnpackSnorm4x8:
1003 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
1004 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001005 case EOpAny:
1006 case EOpAll:
1007 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1008 break;
1009 case EOpLength:
1010 case EOpDeterminant:
1011 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
1012 break;
1013 case EOpTranspose:
1014 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
1015 static_cast<unsigned char>(mOperand->getType().getRows()),
1016 static_cast<unsigned char>(mOperand->getType().getCols())));
1017 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001018 case EOpIsinf:
1019 case EOpIsnan:
Olli Etuahoa2234302016-08-31 12:05:39 +03001020 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
1021 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001022 case EOpBitfieldReverse:
1023 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
1024 break;
1025 case EOpBitCount:
1026 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1027 break;
1028 case EOpFindLSB:
1029 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1030 break;
1031 case EOpFindMSB:
1032 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1033 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001034 default:
1035 setType(mOperand->getType());
1036 mType.setQualifier(resultQualifier);
1037 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001038 }
Olli Etuahoa2234302016-08-31 12:05:39 +03001039}
Jamie Madillb1a85f42014-08-19 15:23:24 -04001040
Olli Etuahob6fa0432016-09-28 16:28:05 +01001041TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001042 : TIntermExpression(TType(EbtFloat, EbpUndefined)),
Olli Etuahob6fa0432016-09-28 16:28:05 +01001043 mOperand(operand),
1044 mSwizzleOffsets(swizzleOffsets)
1045{
1046 ASSERT(mSwizzleOffsets.size() <= 4);
1047 promote();
1048}
1049
Olli Etuahoa2234302016-08-31 12:05:39 +03001050TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
1051 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
1052{
1053 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001054}
1055
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001056TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1057 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
1058{
1059 promote();
1060}
1061
Olli Etuaho0e99b7a2018-01-12 12:05:48 +02001062TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left,
1063 TIntermTyped *right,
1064 int shaderVersion)
1065{
1066 TIntermBinary *node = new TIntermBinary(EOpComma, left, right);
1067 node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right));
1068 return node;
1069}
1070
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001071TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1072 : TIntermNode(), mSymbol(symbol)
1073{
1074 ASSERT(symbol);
1075 setLine(line);
1076}
1077
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001078TIntermTernary::TIntermTernary(TIntermTyped *cond,
1079 TIntermTyped *trueExpression,
1080 TIntermTyped *falseExpression)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001081 : TIntermExpression(trueExpression->getType()),
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001082 mCondition(cond),
1083 mTrueExpression(trueExpression),
1084 mFalseExpression(falseExpression)
1085{
1086 getTypePointer()->setQualifier(
1087 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1088}
1089
Olli Etuaho81629262017-04-19 11:56:01 +03001090TIntermLoop::TIntermLoop(TLoopType type,
1091 TIntermNode *init,
1092 TIntermTyped *cond,
1093 TIntermTyped *expr,
1094 TIntermBlock *body)
1095 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1096{
1097 // Declaration nodes with no children can appear if all the declarators just added constants to
1098 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1099 if (mInit && mInit->getAsDeclarationNode() &&
1100 mInit->getAsDeclarationNode()->getSequence()->empty())
1101 {
1102 mInit = nullptr;
1103 }
1104}
1105
Olli Etuaho923ecef2017-10-11 12:01:38 +03001106TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
1107 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
1108{
1109 // Prune empty false blocks so that there won't be unnecessary operations done on it.
1110 if (mFalseBlock && mFalseBlock->getSequence()->empty())
1111 {
1112 mFalseBlock = nullptr;
1113 }
1114}
1115
1116TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
1117 : TIntermNode(), mInit(init), mStatementList(statementList)
1118{
1119 ASSERT(mStatementList);
1120}
1121
1122void TIntermSwitch::setStatementList(TIntermBlock *statementList)
1123{
1124 ASSERT(statementList);
1125 mStatementList = statementList;
1126}
1127
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001128// static
1129TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1130 TIntermTyped *trueExpression,
1131 TIntermTyped *falseExpression)
1132{
1133 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1134 falseExpression->getQualifier() == EvqConst)
1135 {
1136 return EvqConst;
1137 }
1138 return EvqTemporary;
1139}
1140
Olli Etuaho765924f2018-01-04 12:48:36 +02001141TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001142{
1143 if (mCondition->getAsConstantUnion())
1144 {
1145 if (mCondition->getAsConstantUnion()->getBConst(0))
1146 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001147 return mTrueExpression;
1148 }
1149 else
1150 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001151 return mFalseExpression;
1152 }
1153 }
1154 return this;
1155}
1156
Olli Etuahob6fa0432016-09-28 16:28:05 +01001157void TIntermSwizzle::promote()
1158{
1159 TQualifier resultQualifier = EvqTemporary;
1160 if (mOperand->getQualifier() == EvqConst)
1161 resultQualifier = EvqConst;
1162
1163 auto numFields = mSwizzleOffsets.size();
1164 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1165 static_cast<unsigned char>(numFields)));
1166}
1167
1168bool TIntermSwizzle::hasDuplicateOffsets() const
1169{
1170 int offsetCount[4] = {0u, 0u, 0u, 0u};
1171 for (const auto offset : mSwizzleOffsets)
1172 {
1173 offsetCount[offset]++;
1174 if (offsetCount[offset] > 1)
1175 {
1176 return true;
1177 }
1178 }
1179 return false;
1180}
1181
Olli Etuaho09b04a22016-12-15 13:30:26 +00001182bool TIntermSwizzle::offsetsMatch(int offset) const
1183{
1184 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1185}
1186
Olli Etuahob6fa0432016-09-28 16:28:05 +01001187void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1188{
1189 for (const int offset : mSwizzleOffsets)
1190 {
1191 switch (offset)
1192 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001193 case 0:
1194 *out << "x";
1195 break;
1196 case 1:
1197 *out << "y";
1198 break;
1199 case 2:
1200 *out << "z";
1201 break;
1202 case 3:
1203 *out << "w";
1204 break;
1205 default:
1206 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001207 }
1208 }
1209}
1210
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001211TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1212 const TIntermTyped *left,
1213 const TIntermTyped *right)
1214{
1215 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1216 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1217 right->getQualifier() != EvqConst)
1218 {
1219 return EvqTemporary;
1220 }
1221 return EvqConst;
1222}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001223
1224// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001225void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001226{
Olli Etuaho1dded802016-08-18 18:13:13 +03001227 ASSERT(!isMultiplication() ||
1228 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1229
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001230 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1231 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001232 if (mOp == EOpComma)
1233 {
1234 setType(mRight->getType());
1235 return;
1236 }
1237
Jamie Madillb1a85f42014-08-19 15:23:24 -04001238 // Base assumption: just make the type the same as the left
1239 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001240 setType(mLeft->getType());
1241
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001242 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001243 // Binary operations results in temporary variables unless both
1244 // operands are const.
1245 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1246 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001247 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001248 getTypePointer()->setQualifier(EvqTemporary);
1249 }
1250
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001251 // Handle indexing ops.
1252 switch (mOp)
1253 {
1254 case EOpIndexDirect:
1255 case EOpIndexIndirect:
1256 if (mLeft->isArray())
1257 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001258 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001259 }
1260 else if (mLeft->isMatrix())
1261 {
1262 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1263 static_cast<unsigned char>(mLeft->getRows())));
1264 }
1265 else if (mLeft->isVector())
1266 {
1267 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1268 }
1269 else
1270 {
1271 UNREACHABLE();
1272 }
1273 return;
1274 case EOpIndexDirectStruct:
1275 {
1276 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1277 const int i = mRight->getAsConstantUnion()->getIConst(0);
1278 setType(*fields[i]->type());
1279 getTypePointer()->setQualifier(resultQualifier);
1280 return;
1281 }
1282 case EOpIndexDirectInterfaceBlock:
1283 {
1284 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1285 const int i = mRight->getAsConstantUnion()->getIConst(0);
1286 setType(*fields[i]->type());
1287 getTypePointer()->setQualifier(resultQualifier);
1288 return;
1289 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001290 default:
1291 break;
1292 }
1293
1294 ASSERT(mLeft->isArray() == mRight->isArray());
1295
1296 // The result gets promoted to the highest precision.
1297 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1298 getTypePointer()->setPrecision(higherPrecision);
1299
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001300 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001301
1302 //
1303 // All scalars or structs. Code after this test assumes this case is removed!
1304 //
1305 if (nominalSize == 1)
1306 {
1307 switch (mOp)
1308 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001309 //
1310 // Promote to conditional
1311 //
1312 case EOpEqual:
1313 case EOpNotEqual:
1314 case EOpLessThan:
1315 case EOpGreaterThan:
1316 case EOpLessThanEqual:
1317 case EOpGreaterThanEqual:
1318 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1319 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001320
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001321 //
1322 // And and Or operate on conditionals
1323 //
1324 case EOpLogicalAnd:
1325 case EOpLogicalXor:
1326 case EOpLogicalOr:
1327 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1328 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1329 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001330
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001331 default:
1332 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001333 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001334 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001335 }
1336
1337 // If we reach here, at least one of the operands is vector or matrix.
1338 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001339 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001340
Jamie Madillb1a85f42014-08-19 15:23:24 -04001341 switch (mOp)
1342 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001343 case EOpMul:
1344 break;
1345 case EOpMatrixTimesScalar:
1346 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001347 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001348 setType(TType(basicType, higherPrecision, resultQualifier,
1349 static_cast<unsigned char>(mRight->getCols()),
1350 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001351 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001352 break;
1353 case EOpMatrixTimesVector:
1354 setType(TType(basicType, higherPrecision, resultQualifier,
1355 static_cast<unsigned char>(mLeft->getRows()), 1));
1356 break;
1357 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001358 setType(TType(basicType, higherPrecision, resultQualifier,
1359 static_cast<unsigned char>(mRight->getCols()),
1360 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001361 break;
1362 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001363 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001364 static_cast<unsigned char>(nominalSize), 1));
1365 break;
1366 case EOpVectorTimesMatrix:
1367 setType(TType(basicType, higherPrecision, resultQualifier,
1368 static_cast<unsigned char>(mRight->getCols()), 1));
1369 break;
1370 case EOpMulAssign:
1371 case EOpVectorTimesScalarAssign:
1372 case EOpVectorTimesMatrixAssign:
1373 case EOpMatrixTimesScalarAssign:
1374 case EOpMatrixTimesMatrixAssign:
1375 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1376 break;
1377 case EOpAssign:
1378 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001379 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1380 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1381 break;
1382 case EOpAdd:
1383 case EOpSub:
1384 case EOpDiv:
1385 case EOpIMod:
1386 case EOpBitShiftLeft:
1387 case EOpBitShiftRight:
1388 case EOpBitwiseAnd:
1389 case EOpBitwiseXor:
1390 case EOpBitwiseOr:
1391 case EOpAddAssign:
1392 case EOpSubAssign:
1393 case EOpDivAssign:
1394 case EOpIModAssign:
1395 case EOpBitShiftLeftAssign:
1396 case EOpBitShiftRightAssign:
1397 case EOpBitwiseAndAssign:
1398 case EOpBitwiseXorAssign:
1399 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001400 {
1401 const int secondarySize =
1402 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1403 setType(TType(basicType, higherPrecision, resultQualifier,
1404 static_cast<unsigned char>(nominalSize),
1405 static_cast<unsigned char>(secondarySize)));
1406 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001407 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001408 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001409 case EOpEqual:
1410 case EOpNotEqual:
1411 case EOpLessThan:
1412 case EOpGreaterThan:
1413 case EOpLessThanEqual:
1414 case EOpGreaterThanEqual:
1415 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1416 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001417 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001418 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001419
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001420 case EOpIndexDirect:
1421 case EOpIndexIndirect:
1422 case EOpIndexDirectInterfaceBlock:
1423 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001424 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001425 UNREACHABLE();
1426 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001427 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001428 UNREACHABLE();
1429 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001430 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001431}
1432
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001433bool TIntermConstantUnion::hasConstantValue() const
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001434{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001435 return true;
1436}
1437
1438const TConstantUnion *TIntermConstantUnion::getConstantValue() const
1439{
1440 return mUnionArrayPointer;
1441}
1442
1443const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
1444 const TConstantUnion *constArray,
1445 int index)
1446{
1447 if (type.isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001448 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001449 ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
1450 TType arrayElementType(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001451 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001452 size_t arrayElementSize = arrayElementType.getObjectSize();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001453 return &constArray[arrayElementSize * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001454 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001455 else if (type.isMatrix())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001456 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001457 ASSERT(index < type.getCols());
1458 int size = type.getRows();
1459 return &constArray[size * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001460 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001461 else if (type.isVector())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001462 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001463 ASSERT(index < type.getNominalSize());
1464 return &constArray[index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001465 }
1466 else
1467 {
1468 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001469 return nullptr;
1470 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001471}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001472
Olli Etuaho765924f2018-01-04 12:48:36 +02001473TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001474{
1475 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1476 if (operandConstant == nullptr)
1477 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001478 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001479 }
1480
1481 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1482 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1483 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001484 constArray[i] = *TIntermConstantUnion::FoldIndexing(
1485 operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
Olli Etuahob6fa0432016-09-28 16:28:05 +01001486 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001487 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001488}
1489
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001490TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1491{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001492 const TConstantUnion *rightConstant = mRight->getConstantValue();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001493 switch (mOp)
1494 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001495 case EOpComma:
1496 {
1497 if (mLeft->hasSideEffects())
1498 {
1499 return this;
1500 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001501 return mRight;
1502 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001503 case EOpIndexDirect:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001504 case EOpIndexDirectStruct:
1505 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001506 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001507 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001508 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001509 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001510 size_t index = static_cast<size_t>(rightConstant->getIConst());
1511 TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
1512 if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
1513 !leftAggregate->hasSideEffects())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001514 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001515 ASSERT(index < leftAggregate->getSequence()->size());
1516 // This transformation can't add complexity as we're eliminating the constructor
1517 // entirely.
1518 return leftAggregate->getSequence()->at(index)->getAsTyped();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001519 }
1520
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001521 // If the indexed value is already a constant union, we can't increase duplication of
1522 // data by folding the indexing. Also fold the node in case it's generally beneficial to
1523 // replace this type of node with a constant union even if that would mean duplicating
1524 // data.
1525 if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
1526 {
1527 const TConstantUnion *constantValue = getConstantValue();
1528 if (constantValue == nullptr)
1529 {
1530 return this;
1531 }
1532 return CreateFoldedNode(constantValue, this);
1533 }
1534 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001535 }
1536 case EOpIndexIndirect:
1537 case EOpIndexDirectInterfaceBlock:
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001538 case EOpInitialize:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001539 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001540 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001541 default:
1542 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001543 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001544 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001545 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001546 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001547 const TConstantUnion *leftConstant = mLeft->getConstantValue();
1548 if (leftConstant == nullptr)
1549 {
1550 return this;
1551 }
1552 const TConstantUnion *constArray =
1553 TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
1554 mRight->getType(), diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001555 if (!constArray)
1556 {
1557 return this;
1558 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001559 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001560 }
1561 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001562}
1563
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001564bool TIntermBinary::hasConstantValue() const
1565{
1566 switch (mOp)
1567 {
1568 case EOpIndexDirect:
1569 case EOpIndexDirectStruct:
1570 {
1571 if (mLeft->hasConstantValue() && mRight->hasConstantValue())
1572 {
1573 return true;
1574 }
Nico Weber41b072b2018-02-09 10:01:32 -05001575 break;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001576 }
1577 default:
1578 break;
1579 }
1580 return false;
1581}
1582
1583const TConstantUnion *TIntermBinary::getConstantValue() const
1584{
1585 if (!hasConstantValue())
1586 {
1587 return nullptr;
1588 }
1589
1590 const TConstantUnion *leftConstantValue = mLeft->getConstantValue();
1591 int index = mRight->getConstantValue()->getIConst();
1592 const TConstantUnion *constIndexingResult = nullptr;
1593 if (mOp == EOpIndexDirect)
1594 {
1595 constIndexingResult =
1596 TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
1597 }
1598 else
1599 {
1600 ASSERT(mOp == EOpIndexDirectStruct);
1601 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1602
1603 size_t previousFieldsSize = 0;
1604 for (int i = 0; i < index; ++i)
1605 {
1606 previousFieldsSize += fields[i]->type()->getObjectSize();
1607 }
1608 constIndexingResult = leftConstantValue + previousFieldsSize;
1609 }
1610 return constIndexingResult;
1611}
1612
Olli Etuahof119a262016-08-19 15:54:22 +03001613TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001614{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301615 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001616
1617 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301618 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001619 // The size of runtime-sized arrays may only be determined at runtime.
1620 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001621 {
1622 return this;
1623 }
1624 constArray = new TConstantUnion[1];
1625 constArray->setIConst(mOperand->getOutermostArraySize());
1626 }
1627 else
1628 {
1629 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1630 if (operandConstant == nullptr)
1631 {
1632 return this;
1633 }
1634
1635 switch (mOp)
1636 {
1637 case EOpAny:
1638 case EOpAll:
1639 case EOpLength:
1640 case EOpTranspose:
1641 case EOpDeterminant:
1642 case EOpInverse:
1643 case EOpPackSnorm2x16:
1644 case EOpUnpackSnorm2x16:
1645 case EOpPackUnorm2x16:
1646 case EOpUnpackUnorm2x16:
1647 case EOpPackHalf2x16:
1648 case EOpUnpackHalf2x16:
1649 case EOpPackUnorm4x8:
1650 case EOpPackSnorm4x8:
1651 case EOpUnpackUnorm4x8:
1652 case EOpUnpackSnorm4x8:
1653 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1654 break;
1655 default:
1656 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1657 break;
1658 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301659 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001660 if (constArray == nullptr)
1661 {
1662 return this;
1663 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001664 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001665}
1666
Olli Etuahof119a262016-08-19 15:54:22 +03001667TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001668{
1669 // Make sure that all params are constant before actual constant folding.
1670 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001671 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001672 if (param->getAsConstantUnion() == nullptr)
1673 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001674 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001675 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001676 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001677 const TConstantUnion *constArray = nullptr;
Olli Etuaho1d122782015-11-06 15:35:17 +02001678 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001679 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001680 if (mType.canReplaceWithConstantUnion())
Olli Etuaho765924f2018-01-04 12:48:36 +02001681 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001682 constArray = getConstantValue();
Olli Etuaho765924f2018-01-04 12:48:36 +02001683 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001684 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001685 else if (CanFoldAggregateBuiltInOp(mOp))
Olli Etuaho2768bc82017-12-12 11:51:48 +02001686 {
Olli Etuahof119a262016-08-19 15:54:22 +03001687 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001688 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001689 if (constArray == nullptr)
1690 {
1691 return this;
1692 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001693 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001694}
1695
Jamie Madillb1a85f42014-08-19 15:23:24 -04001696//
1697// The fold functions see if an operation on a constant can be done in place,
1698// without generating run-time code.
1699//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001700// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001701//
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001702const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
1703 const TConstantUnion *leftArray,
1704 const TType &leftType,
1705 const TConstantUnion *rightArray,
1706 const TType &rightType,
1707 TDiagnostics *diagnostics,
1708 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001709{
Olli Etuahof119a262016-08-19 15:54:22 +03001710 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001711
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001712 size_t objectSize = leftType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001713
1714 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001715 if (rightType.getObjectSize() == 1 && objectSize > 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001716 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001717 rightArray = Vectorize(*rightArray, objectSize);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001718 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001719 else if (rightType.getObjectSize() > 1 && objectSize == 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001720 {
1721 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001722 leftArray = Vectorize(*leftArray, rightType.getObjectSize());
1723 objectSize = rightType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001724 }
1725
1726 TConstantUnion *resultArray = nullptr;
1727
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001728 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001729 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001730 case EOpAdd:
1731 resultArray = new TConstantUnion[objectSize];
1732 for (size_t i = 0; i < objectSize; i++)
1733 resultArray[i] =
1734 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1735 break;
1736 case EOpSub:
1737 resultArray = new TConstantUnion[objectSize];
1738 for (size_t i = 0; i < objectSize; i++)
1739 resultArray[i] =
1740 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1741 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001742
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001743 case EOpMul:
1744 case EOpVectorTimesScalar:
1745 case EOpMatrixTimesScalar:
1746 resultArray = new TConstantUnion[objectSize];
1747 for (size_t i = 0; i < objectSize; i++)
1748 resultArray[i] =
1749 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1750 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001751
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001752 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001753 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001754 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001755 ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001756
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001757 const int leftCols = leftType.getCols();
1758 const int leftRows = leftType.getRows();
1759 const int rightCols = rightType.getCols();
1760 const int rightRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001761 const int resultCols = rightCols;
1762 const int resultRows = leftRows;
1763
1764 resultArray = new TConstantUnion[resultCols * resultRows];
1765 for (int row = 0; row < resultRows; row++)
1766 {
1767 for (int column = 0; column < resultCols; column++)
1768 {
1769 resultArray[resultRows * column + row].setFConst(0.0f);
1770 for (int i = 0; i < leftCols; i++)
1771 {
1772 resultArray[resultRows * column + row].setFConst(
1773 resultArray[resultRows * column + row].getFConst() +
1774 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001775 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001776 }
1777 }
1778 }
1779 }
1780 break;
1781
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001782 case EOpDiv:
1783 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001784 {
1785 resultArray = new TConstantUnion[objectSize];
1786 for (size_t i = 0; i < objectSize; i++)
1787 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001788 switch (leftType.getBasicType())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001789 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001790 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001791 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001792 ASSERT(op == EOpDiv);
1793 float dividend = leftArray[i].getFConst();
1794 float divisor = rightArray[i].getFConst();
1795 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001796 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001797 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001798 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001799 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001800 line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001801 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001802 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001803 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001804 }
1805 else
1806 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001807 diagnostics->warning(line, "Divide by zero during constant folding",
1808 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001809 bool negativeResult =
1810 std::signbit(dividend) != std::signbit(divisor);
1811 resultArray[i].setFConst(
1812 negativeResult ? -std::numeric_limits<float>::infinity()
1813 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001814 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001815 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001816 else if (gl::isInf(dividend) && gl::isInf(divisor))
1817 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001818 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001819 "Infinity divided by infinity during constant "
1820 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001821 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001822 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1823 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001824 else
1825 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001826 float result = dividend / divisor;
1827 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001828 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001829 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001830 line, "Constant folded division overflowed to infinity", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001831 }
1832 resultArray[i].setFConst(result);
1833 }
1834 break;
1835 }
1836 case EbtInt:
1837 if (rightArray[i] == 0)
1838 {
1839 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001840 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001841 resultArray[i].setIConst(INT_MAX);
1842 }
1843 else
1844 {
1845 int lhs = leftArray[i].getIConst();
1846 int divisor = rightArray[i].getIConst();
1847 if (op == EOpDiv)
1848 {
1849 // Check for the special case where the minimum representable number
1850 // is
1851 // divided by -1. If left alone this leads to integer overflow in
1852 // C++.
1853 // ESSL 3.00.6 section 4.1.3 Integers:
1854 // "However, for the case where the minimum representable value is
1855 // divided by -1, it is allowed to return either the minimum
1856 // representable value or the maximum representable value."
1857 if (lhs == -0x7fffffff - 1 && divisor == -1)
1858 {
1859 resultArray[i].setIConst(0x7fffffff);
1860 }
1861 else
1862 {
1863 resultArray[i].setIConst(lhs / divisor);
1864 }
Olli Etuahod4453572016-09-27 13:21:46 +01001865 }
1866 else
1867 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001868 ASSERT(op == EOpIMod);
1869 if (lhs < 0 || divisor < 0)
1870 {
1871 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1872 // when
1873 // either one of the operands is negative.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001874 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001875 "Negative modulus operator operand "
1876 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001877 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001878 resultArray[i].setIConst(0);
1879 }
1880 else
1881 {
1882 resultArray[i].setIConst(lhs % divisor);
1883 }
Olli Etuahod4453572016-09-27 13:21:46 +01001884 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001885 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001886 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001887
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001888 case EbtUInt:
1889 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001890 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001891 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001892 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001893 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001894 }
1895 else
1896 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001897 if (op == EOpDiv)
1898 {
1899 resultArray[i].setUConst(leftArray[i].getUConst() /
1900 rightArray[i].getUConst());
1901 }
1902 else
1903 {
1904 ASSERT(op == EOpIMod);
1905 resultArray[i].setUConst(leftArray[i].getUConst() %
1906 rightArray[i].getUConst());
1907 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001908 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001909 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001910
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001911 default:
1912 UNREACHABLE();
1913 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001914 }
1915 }
1916 }
1917 break;
1918
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001919 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001920 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001921 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001922 ASSERT(rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001923
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001924 const int matrixCols = leftType.getCols();
1925 const int matrixRows = leftType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001926
1927 resultArray = new TConstantUnion[matrixRows];
1928
1929 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1930 {
1931 resultArray[matrixRow].setFConst(0.0f);
1932 for (int col = 0; col < matrixCols; col++)
1933 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001934 resultArray[matrixRow].setFConst(
1935 resultArray[matrixRow].getFConst() +
1936 leftArray[col * matrixRows + matrixRow].getFConst() *
1937 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001938 }
1939 }
1940 }
1941 break;
1942
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001943 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001944 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001945 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001946 ASSERT(leftType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001947
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001948 const int matrixCols = rightType.getCols();
1949 const int matrixRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001950
1951 resultArray = new TConstantUnion[matrixCols];
1952
1953 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1954 {
1955 resultArray[matrixCol].setFConst(0.0f);
1956 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1957 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001958 resultArray[matrixCol].setFConst(
1959 resultArray[matrixCol].getFConst() +
1960 leftArray[matrixRow].getFConst() *
1961 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001962 }
1963 }
1964 }
1965 break;
1966
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001967 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001968 {
1969 resultArray = new TConstantUnion[objectSize];
1970 for (size_t i = 0; i < objectSize; i++)
1971 {
1972 resultArray[i] = leftArray[i] && rightArray[i];
1973 }
1974 }
1975 break;
1976
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001977 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001978 {
1979 resultArray = new TConstantUnion[objectSize];
1980 for (size_t i = 0; i < objectSize; i++)
1981 {
1982 resultArray[i] = leftArray[i] || rightArray[i];
1983 }
1984 }
1985 break;
1986
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001987 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001988 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001989 ASSERT(leftType.getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001990 resultArray = new TConstantUnion[objectSize];
1991 for (size_t i = 0; i < objectSize; i++)
1992 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001993 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001994 }
1995 }
1996 break;
1997
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001998 case EOpBitwiseAnd:
1999 resultArray = new TConstantUnion[objectSize];
2000 for (size_t i = 0; i < objectSize; i++)
2001 resultArray[i] = leftArray[i] & rightArray[i];
2002 break;
2003 case EOpBitwiseXor:
2004 resultArray = new TConstantUnion[objectSize];
2005 for (size_t i = 0; i < objectSize; i++)
2006 resultArray[i] = leftArray[i] ^ rightArray[i];
2007 break;
2008 case EOpBitwiseOr:
2009 resultArray = new TConstantUnion[objectSize];
2010 for (size_t i = 0; i < objectSize; i++)
2011 resultArray[i] = leftArray[i] | rightArray[i];
2012 break;
2013 case EOpBitShiftLeft:
2014 resultArray = new TConstantUnion[objectSize];
2015 for (size_t i = 0; i < objectSize; i++)
2016 resultArray[i] =
2017 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
2018 break;
2019 case EOpBitShiftRight:
2020 resultArray = new TConstantUnion[objectSize];
2021 for (size_t i = 0; i < objectSize; i++)
2022 resultArray[i] =
2023 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
2024 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002025
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002026 case EOpLessThan:
2027 ASSERT(objectSize == 1);
2028 resultArray = new TConstantUnion[1];
2029 resultArray->setBConst(*leftArray < *rightArray);
2030 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002031
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002032 case EOpGreaterThan:
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 EOpLessThanEqual:
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 EOpGreaterThanEqual:
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 EOpEqual:
2051 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002052 {
2053 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002054 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002055 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002056 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002057 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002058 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002059 equal = false;
2060 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002061 }
2062 }
2063 if (op == EOpEqual)
2064 {
2065 resultArray->setBConst(equal);
2066 }
2067 else
2068 {
2069 resultArray->setBConst(!equal);
2070 }
2071 }
2072 break;
2073
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002074 default:
2075 UNREACHABLE();
2076 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002077 }
2078 return resultArray;
2079}
2080
Olli Etuahof119a262016-08-19 15:54:22 +03002081// The fold functions do operations on a constant at GLSL compile time, without generating run-time
2082// code. Returns the constant value to keep using. Nullptr should not be returned.
2083TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04002084{
Olli Etuahof119a262016-08-19 15:54:22 +03002085 // Do operations where the return type may have a different number of components compared to the
2086 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04002087
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002088 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002089 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302090
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002091 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302092 TConstantUnion *resultArray = nullptr;
2093 switch (op)
2094 {
Olli Etuahof119a262016-08-19 15:54:22 +03002095 case EOpAny:
2096 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302097 resultArray = new TConstantUnion();
2098 resultArray->setBConst(false);
2099 for (size_t i = 0; i < objectSize; i++)
2100 {
2101 if (operandArray[i].getBConst())
2102 {
2103 resultArray->setBConst(true);
2104 break;
2105 }
2106 }
2107 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302108
Olli Etuahof119a262016-08-19 15:54:22 +03002109 case EOpAll:
2110 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302111 resultArray = new TConstantUnion();
2112 resultArray->setBConst(true);
2113 for (size_t i = 0; i < objectSize; i++)
2114 {
2115 if (!operandArray[i].getBConst())
2116 {
2117 resultArray->setBConst(false);
2118 break;
2119 }
2120 }
2121 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302122
Olli Etuahof119a262016-08-19 15:54:22 +03002123 case EOpLength:
2124 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302125 resultArray = new TConstantUnion();
2126 resultArray->setFConst(VectorLength(operandArray, objectSize));
2127 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302128
Olli Etuahof119a262016-08-19 15:54:22 +03002129 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302130 {
Olli Etuahof119a262016-08-19 15:54:22 +03002131 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302132 resultArray = new TConstantUnion[objectSize];
2133 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002134 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302135 SetUnionArrayFromMatrix(result, resultArray);
2136 break;
2137 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302138
Olli Etuahof119a262016-08-19 15:54:22 +03002139 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302140 {
Olli Etuahof119a262016-08-19 15:54:22 +03002141 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302142 unsigned int size = getType().getNominalSize();
2143 ASSERT(size >= 2 && size <= 4);
2144 resultArray = new TConstantUnion();
2145 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
2146 break;
2147 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302148
Olli Etuahof119a262016-08-19 15:54:22 +03002149 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302150 {
Olli Etuahof119a262016-08-19 15:54:22 +03002151 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302152 unsigned int size = getType().getNominalSize();
2153 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03002154 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05302155 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
2156 SetUnionArrayFromMatrix(result, resultArray);
2157 break;
2158 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302159
Olli Etuahof119a262016-08-19 15:54:22 +03002160 case EOpPackSnorm2x16:
2161 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302162 ASSERT(getType().getNominalSize() == 2);
2163 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002164 resultArray->setUConst(
2165 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302166 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302167
Olli Etuahof119a262016-08-19 15:54:22 +03002168 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302169 {
Olli Etuahof119a262016-08-19 15:54:22 +03002170 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302171 resultArray = new TConstantUnion[2];
2172 float f1, f2;
2173 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2174 resultArray[0].setFConst(f1);
2175 resultArray[1].setFConst(f2);
2176 break;
2177 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302178
Olli Etuahof119a262016-08-19 15:54:22 +03002179 case EOpPackUnorm2x16:
2180 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302181 ASSERT(getType().getNominalSize() == 2);
2182 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002183 resultArray->setUConst(
2184 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302185 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302186
Olli Etuahof119a262016-08-19 15:54:22 +03002187 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302188 {
Olli Etuahof119a262016-08-19 15:54:22 +03002189 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302190 resultArray = new TConstantUnion[2];
2191 float f1, f2;
2192 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2193 resultArray[0].setFConst(f1);
2194 resultArray[1].setFConst(f2);
2195 break;
2196 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302197
Olli Etuahof119a262016-08-19 15:54:22 +03002198 case EOpPackHalf2x16:
2199 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302200 ASSERT(getType().getNominalSize() == 2);
2201 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002202 resultArray->setUConst(
2203 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302204 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302205
Olli Etuahof119a262016-08-19 15:54:22 +03002206 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302207 {
Olli Etuahof119a262016-08-19 15:54:22 +03002208 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302209 resultArray = new TConstantUnion[2];
2210 float f1, f2;
2211 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2212 resultArray[0].setFConst(f1);
2213 resultArray[1].setFConst(f2);
2214 break;
2215 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302216
Olli Etuaho25aef452017-01-29 16:15:44 -08002217 case EOpPackUnorm4x8:
2218 {
2219 ASSERT(getType().getBasicType() == EbtFloat);
2220 resultArray = new TConstantUnion();
2221 resultArray->setUConst(
2222 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2223 operandArray[2].getFConst(), operandArray[3].getFConst()));
2224 break;
2225 }
2226 case EOpPackSnorm4x8:
2227 {
2228 ASSERT(getType().getBasicType() == EbtFloat);
2229 resultArray = new TConstantUnion();
2230 resultArray->setUConst(
2231 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2232 operandArray[2].getFConst(), operandArray[3].getFConst()));
2233 break;
2234 }
2235 case EOpUnpackUnorm4x8:
2236 {
2237 ASSERT(getType().getBasicType() == EbtUInt);
2238 resultArray = new TConstantUnion[4];
2239 float f[4];
2240 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2241 for (size_t i = 0; i < 4; ++i)
2242 {
2243 resultArray[i].setFConst(f[i]);
2244 }
2245 break;
2246 }
2247 case EOpUnpackSnorm4x8:
2248 {
2249 ASSERT(getType().getBasicType() == EbtUInt);
2250 resultArray = new TConstantUnion[4];
2251 float f[4];
2252 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2253 for (size_t i = 0; i < 4; ++i)
2254 {
2255 resultArray[i].setFConst(f[i]);
2256 }
2257 break;
2258 }
2259
Olli Etuahof119a262016-08-19 15:54:22 +03002260 default:
2261 UNREACHABLE();
2262 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302263 }
2264
2265 return resultArray;
2266}
2267
Olli Etuahof119a262016-08-19 15:54:22 +03002268TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2269 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302270{
Olli Etuahof119a262016-08-19 15:54:22 +03002271 // Do unary operations where each component of the result is computed based on the corresponding
2272 // component of the operand. Also folds normalize, though the divisor in that case takes all
2273 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302274
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002275 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002276 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002277
2278 size_t objectSize = getType().getObjectSize();
2279
Arun Patoleab2b9a22015-07-06 18:27:56 +05302280 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2281 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302282 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002283 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302284 {
Olli Etuahof119a262016-08-19 15:54:22 +03002285 case EOpNegative:
2286 switch (getType().getBasicType())
2287 {
2288 case EbtFloat:
2289 resultArray[i].setFConst(-operandArray[i].getFConst());
2290 break;
2291 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002292 if (operandArray[i] == std::numeric_limits<int>::min())
2293 {
2294 // The minimum representable integer doesn't have a positive
2295 // counterpart, rather the negation overflows and in ESSL is supposed to
2296 // wrap back to the minimum representable integer. Make sure that we
2297 // don't actually let the negation overflow, which has undefined
2298 // behavior in C++.
2299 resultArray[i].setIConst(std::numeric_limits<int>::min());
2300 }
2301 else
2302 {
2303 resultArray[i].setIConst(-operandArray[i].getIConst());
2304 }
Olli Etuahof119a262016-08-19 15:54:22 +03002305 break;
2306 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002307 if (operandArray[i] == 0x80000000u)
2308 {
2309 resultArray[i].setUConst(0x80000000u);
2310 }
2311 else
2312 {
2313 resultArray[i].setUConst(static_cast<unsigned int>(
2314 -static_cast<int>(operandArray[i].getUConst())));
2315 }
Olli Etuahof119a262016-08-19 15:54:22 +03002316 break;
2317 default:
2318 UNREACHABLE();
2319 return nullptr;
2320 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302321 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302322
Olli Etuahof119a262016-08-19 15:54:22 +03002323 case EOpPositive:
2324 switch (getType().getBasicType())
2325 {
2326 case EbtFloat:
2327 resultArray[i].setFConst(operandArray[i].getFConst());
2328 break;
2329 case EbtInt:
2330 resultArray[i].setIConst(operandArray[i].getIConst());
2331 break;
2332 case EbtUInt:
2333 resultArray[i].setUConst(static_cast<unsigned int>(
2334 static_cast<int>(operandArray[i].getUConst())));
2335 break;
2336 default:
2337 UNREACHABLE();
2338 return nullptr;
2339 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302340 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302341
Olli Etuahof119a262016-08-19 15:54:22 +03002342 case EOpLogicalNot:
2343 switch (getType().getBasicType())
2344 {
2345 case EbtBool:
2346 resultArray[i].setBConst(!operandArray[i].getBConst());
2347 break;
2348 default:
2349 UNREACHABLE();
2350 return nullptr;
2351 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302352 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302353
Olli Etuahof119a262016-08-19 15:54:22 +03002354 case EOpBitwiseNot:
2355 switch (getType().getBasicType())
2356 {
2357 case EbtInt:
2358 resultArray[i].setIConst(~operandArray[i].getIConst());
2359 break;
2360 case EbtUInt:
2361 resultArray[i].setUConst(~operandArray[i].getUConst());
2362 break;
2363 default:
2364 UNREACHABLE();
2365 return nullptr;
2366 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302367 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302368
Olli Etuahof119a262016-08-19 15:54:22 +03002369 case EOpRadians:
2370 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302371 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2372 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302373
Olli Etuahof119a262016-08-19 15:54:22 +03002374 case EOpDegrees:
2375 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302376 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2377 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302378
Olli Etuahof119a262016-08-19 15:54:22 +03002379 case EOpSin:
2380 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302381 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302382
Olli Etuahof119a262016-08-19 15:54:22 +03002383 case EOpCos:
2384 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2385 break;
2386
2387 case EOpTan:
2388 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2389 break;
2390
2391 case EOpAsin:
2392 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2393 // 0.
2394 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2395 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2396 diagnostics, &resultArray[i]);
2397 else
2398 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2399 break;
2400
2401 case EOpAcos:
2402 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2403 // 0.
2404 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2405 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2406 diagnostics, &resultArray[i]);
2407 else
2408 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2409 break;
2410
2411 case EOpAtan:
2412 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2413 break;
2414
2415 case EOpSinh:
2416 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2417 break;
2418
2419 case EOpCosh:
2420 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2421 break;
2422
2423 case EOpTanh:
2424 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2425 break;
2426
2427 case EOpAsinh:
2428 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2429 break;
2430
2431 case EOpAcosh:
2432 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2433 if (operandArray[i].getFConst() < 1.0f)
2434 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2435 diagnostics, &resultArray[i]);
2436 else
2437 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2438 break;
2439
2440 case EOpAtanh:
2441 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2442 // 0.
2443 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2444 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2445 diagnostics, &resultArray[i]);
2446 else
2447 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2448 break;
2449
2450 case EOpAbs:
2451 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302452 {
Olli Etuahof119a262016-08-19 15:54:22 +03002453 case EbtFloat:
2454 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2455 break;
2456 case EbtInt:
2457 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2458 break;
2459 default:
2460 UNREACHABLE();
2461 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302462 }
2463 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002464
2465 case EOpSign:
2466 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302467 {
Olli Etuahof119a262016-08-19 15:54:22 +03002468 case EbtFloat:
2469 {
2470 float fConst = operandArray[i].getFConst();
2471 float fResult = 0.0f;
2472 if (fConst > 0.0f)
2473 fResult = 1.0f;
2474 else if (fConst < 0.0f)
2475 fResult = -1.0f;
2476 resultArray[i].setFConst(fResult);
2477 break;
2478 }
2479 case EbtInt:
2480 {
2481 int iConst = operandArray[i].getIConst();
2482 int iResult = 0;
2483 if (iConst > 0)
2484 iResult = 1;
2485 else if (iConst < 0)
2486 iResult = -1;
2487 resultArray[i].setIConst(iResult);
2488 break;
2489 }
2490 default:
2491 UNREACHABLE();
2492 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302493 }
2494 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302495
Olli Etuahof119a262016-08-19 15:54:22 +03002496 case EOpFloor:
2497 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2498 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302499
Olli Etuahof119a262016-08-19 15:54:22 +03002500 case EOpTrunc:
2501 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2502 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302503
Olli Etuahof119a262016-08-19 15:54:22 +03002504 case EOpRound:
2505 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2506 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302507
Olli Etuahof119a262016-08-19 15:54:22 +03002508 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302509 {
Olli Etuahof119a262016-08-19 15:54:22 +03002510 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302511 float x = operandArray[i].getFConst();
2512 float result;
2513 float fractPart = modff(x, &result);
2514 if (fabsf(fractPart) == 0.5f)
2515 result = 2.0f * roundf(x / 2.0f);
2516 else
2517 result = roundf(x);
2518 resultArray[i].setFConst(result);
2519 break;
2520 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302521
Olli Etuahof119a262016-08-19 15:54:22 +03002522 case EOpCeil:
2523 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2524 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302525
Olli Etuahof119a262016-08-19 15:54:22 +03002526 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302527 {
Olli Etuahof119a262016-08-19 15:54:22 +03002528 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302529 float x = operandArray[i].getFConst();
2530 resultArray[i].setFConst(x - floorf(x));
2531 break;
2532 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302533
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002534 case EOpIsnan:
Olli Etuahof119a262016-08-19 15:54:22 +03002535 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302536 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2537 break;
Arun Patole551279e2015-07-07 18:18:23 +05302538
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002539 case EOpIsinf:
Olli Etuahof119a262016-08-19 15:54:22 +03002540 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302541 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2542 break;
Arun Patole551279e2015-07-07 18:18:23 +05302543
Olli Etuahof119a262016-08-19 15:54:22 +03002544 case EOpFloatBitsToInt:
2545 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302546 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2547 break;
Arun Patole551279e2015-07-07 18:18:23 +05302548
Olli Etuahof119a262016-08-19 15:54:22 +03002549 case EOpFloatBitsToUint:
2550 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302551 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2552 break;
Arun Patole551279e2015-07-07 18:18:23 +05302553
Olli Etuahof119a262016-08-19 15:54:22 +03002554 case EOpIntBitsToFloat:
2555 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302556 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2557 break;
Arun Patole551279e2015-07-07 18:18:23 +05302558
Olli Etuahof119a262016-08-19 15:54:22 +03002559 case EOpUintBitsToFloat:
2560 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302561 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2562 break;
Arun Patole551279e2015-07-07 18:18:23 +05302563
Olli Etuahof119a262016-08-19 15:54:22 +03002564 case EOpExp:
2565 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2566 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302567
Olli Etuahof119a262016-08-19 15:54:22 +03002568 case EOpLog:
2569 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2570 if (operandArray[i].getFConst() <= 0.0f)
2571 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2572 diagnostics, &resultArray[i]);
2573 else
2574 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2575 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302576
Olli Etuahof119a262016-08-19 15:54:22 +03002577 case EOpExp2:
2578 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2579 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302580
Olli Etuahof119a262016-08-19 15:54:22 +03002581 case EOpLog2:
2582 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2583 // And log2f is not available on some plarforms like old android, so just using
2584 // log(x)/log(2) here.
2585 if (operandArray[i].getFConst() <= 0.0f)
2586 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2587 diagnostics, &resultArray[i]);
2588 else
2589 {
2590 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2591 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2592 }
2593 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302594
Olli Etuahof119a262016-08-19 15:54:22 +03002595 case EOpSqrt:
2596 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2597 if (operandArray[i].getFConst() < 0.0f)
2598 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2599 diagnostics, &resultArray[i]);
2600 else
2601 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2602 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302603
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002604 case EOpInversesqrt:
Olli Etuahof119a262016-08-19 15:54:22 +03002605 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2606 // so getting the square root first using builtin function sqrt() and then taking
2607 // its inverse.
2608 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2609 // result to 0.
2610 if (operandArray[i].getFConst() <= 0.0f)
2611 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2612 diagnostics, &resultArray[i]);
2613 else
2614 {
2615 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2616 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2617 }
2618 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302619
Olli Etuahod68924e2017-01-02 17:34:40 +00002620 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002621 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302622 resultArray[i].setBConst(!operandArray[i].getBConst());
2623 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302624
Olli Etuahof119a262016-08-19 15:54:22 +03002625 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302626 {
Olli Etuahof119a262016-08-19 15:54:22 +03002627 ASSERT(getType().getBasicType() == EbtFloat);
2628 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302629 float length = VectorLength(operandArray, objectSize);
2630 if (length)
2631 resultArray[i].setFConst(x / length);
2632 else
Olli Etuahof119a262016-08-19 15:54:22 +03002633 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2634 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302635 break;
2636 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002637 case EOpBitfieldReverse:
2638 {
2639 uint32_t value;
2640 if (getType().getBasicType() == EbtInt)
2641 {
2642 value = static_cast<uint32_t>(operandArray[i].getIConst());
2643 }
2644 else
2645 {
2646 ASSERT(getType().getBasicType() == EbtUInt);
2647 value = operandArray[i].getUConst();
2648 }
2649 uint32_t result = gl::BitfieldReverse(value);
2650 if (getType().getBasicType() == EbtInt)
2651 {
2652 resultArray[i].setIConst(static_cast<int32_t>(result));
2653 }
2654 else
2655 {
2656 resultArray[i].setUConst(result);
2657 }
2658 break;
2659 }
2660 case EOpBitCount:
2661 {
2662 uint32_t value;
2663 if (getType().getBasicType() == EbtInt)
2664 {
2665 value = static_cast<uint32_t>(operandArray[i].getIConst());
2666 }
2667 else
2668 {
2669 ASSERT(getType().getBasicType() == EbtUInt);
2670 value = operandArray[i].getUConst();
2671 }
2672 int result = gl::BitCount(value);
2673 resultArray[i].setIConst(result);
2674 break;
2675 }
2676 case EOpFindLSB:
2677 {
2678 uint32_t value;
2679 if (getType().getBasicType() == EbtInt)
2680 {
2681 value = static_cast<uint32_t>(operandArray[i].getIConst());
2682 }
2683 else
2684 {
2685 ASSERT(getType().getBasicType() == EbtUInt);
2686 value = operandArray[i].getUConst();
2687 }
2688 resultArray[i].setIConst(gl::FindLSB(value));
2689 break;
2690 }
2691 case EOpFindMSB:
2692 {
2693 uint32_t value;
2694 if (getType().getBasicType() == EbtInt)
2695 {
2696 int intValue = operandArray[i].getIConst();
2697 value = static_cast<uint32_t>(intValue);
2698 if (intValue < 0)
2699 {
2700 // Look for zero instead of one in value. This also handles the intValue ==
2701 // -1 special case, where the return value needs to be -1.
2702 value = ~value;
2703 }
2704 }
2705 else
2706 {
2707 ASSERT(getType().getBasicType() == EbtUInt);
2708 value = operandArray[i].getUConst();
2709 }
2710 resultArray[i].setIConst(gl::FindMSB(value));
2711 break;
2712 }
Olli Etuahof119a262016-08-19 15:54:22 +03002713 case EOpDFdx:
2714 case EOpDFdy:
2715 case EOpFwidth:
2716 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302717 // Derivatives of constant arguments should be 0.
2718 resultArray[i].setFConst(0.0f);
2719 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302720
Olli Etuahof119a262016-08-19 15:54:22 +03002721 default:
2722 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302723 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302724 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002725
Arun Patoleab2b9a22015-07-06 18:27:56 +05302726 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002727}
2728
Olli Etuahof119a262016-08-19 15:54:22 +03002729void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2730 FloatTypeUnaryFunc builtinFunc,
2731 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302732{
2733 ASSERT(builtinFunc);
2734
Olli Etuahof119a262016-08-19 15:54:22 +03002735 ASSERT(getType().getBasicType() == EbtFloat);
2736 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302737}
2738
Jamie Madillb1a85f42014-08-19 15:23:24 -04002739// static
Olli Etuahof119a262016-08-19 15:54:22 +03002740TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2741 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302742{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002743 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002744 TIntermSequence *arguments = aggregate->getSequence();
2745 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2746 std::vector<const TConstantUnion *> unionArrays(argsCount);
2747 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002748 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302749 TBasicType basicType = EbtVoid;
2750 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002751 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302752 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002753 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2754 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302755
2756 if (i == 0)
2757 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002758 basicType = argConstant->getType().getBasicType();
2759 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302760 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002761 unionArrays[i] = argConstant->getConstantValue();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002762 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002763 if (objectSizes[i] > maxObjectSize)
2764 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302765 }
2766
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002767 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302768 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002769 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302770 if (objectSizes[i] != maxObjectSize)
2771 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2772 }
Arun Patole274f0702015-05-05 13:33:30 +05302773
Olli Etuahob43846e2015-06-02 18:18:57 +03002774 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002775
2776 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302777 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002778 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302779 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002780 ASSERT(basicType == EbtFloat);
2781 resultArray = new TConstantUnion[maxObjectSize];
2782 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302783 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002784 float y = unionArrays[0][i].getFConst();
2785 float x = unionArrays[1][i].getFConst();
2786 // Results are undefined if x and y are both 0.
2787 if (x == 0.0f && y == 0.0f)
2788 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2789 else
2790 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302791 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002792 break;
2793 }
Arun Patolebf790422015-05-18 17:53:04 +05302794
Olli Etuaho51182ab2017-01-22 00:12:29 +00002795 case EOpPow:
2796 {
2797 ASSERT(basicType == EbtFloat);
2798 resultArray = new TConstantUnion[maxObjectSize];
2799 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302800 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002801 float x = unionArrays[0][i].getFConst();
2802 float y = unionArrays[1][i].getFConst();
2803 // Results are undefined if x < 0.
2804 // Results are undefined if x = 0 and y <= 0.
2805 if (x < 0.0f)
2806 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2807 else if (x == 0.0f && y <= 0.0f)
2808 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2809 else
2810 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302811 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002812 break;
2813 }
Arun Patolebf790422015-05-18 17:53:04 +05302814
Olli Etuaho51182ab2017-01-22 00:12:29 +00002815 case EOpMod:
2816 {
2817 ASSERT(basicType == EbtFloat);
2818 resultArray = new TConstantUnion[maxObjectSize];
2819 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302820 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002821 float x = unionArrays[0][i].getFConst();
2822 float y = unionArrays[1][i].getFConst();
2823 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302824 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002825 break;
2826 }
Arun Patolebf790422015-05-18 17:53:04 +05302827
Olli Etuaho51182ab2017-01-22 00:12:29 +00002828 case EOpMin:
2829 {
2830 resultArray = new TConstantUnion[maxObjectSize];
2831 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302832 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002833 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302834 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002835 case EbtFloat:
2836 resultArray[i].setFConst(
2837 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2838 break;
2839 case EbtInt:
2840 resultArray[i].setIConst(
2841 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2842 break;
2843 case EbtUInt:
2844 resultArray[i].setUConst(
2845 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2846 break;
2847 default:
2848 UNREACHABLE();
2849 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302850 }
2851 }
2852 break;
Arun Patole274f0702015-05-05 13:33:30 +05302853 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002854
2855 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302856 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002857 resultArray = new TConstantUnion[maxObjectSize];
2858 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302859 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002860 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302861 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002862 case EbtFloat:
2863 resultArray[i].setFConst(
2864 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2865 break;
2866 case EbtInt:
2867 resultArray[i].setIConst(
2868 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2869 break;
2870 case EbtUInt:
2871 resultArray[i].setUConst(
2872 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2873 break;
2874 default:
2875 UNREACHABLE();
2876 break;
Arun Patole274f0702015-05-05 13:33:30 +05302877 }
2878 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002879 break;
Arun Patole274f0702015-05-05 13:33:30 +05302880 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002881
2882 case EOpStep:
2883 {
2884 ASSERT(basicType == EbtFloat);
2885 resultArray = new TConstantUnion[maxObjectSize];
2886 for (size_t i = 0; i < maxObjectSize; i++)
2887 resultArray[i].setFConst(
2888 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2889 break;
2890 }
2891
2892 case EOpLessThanComponentWise:
2893 {
2894 resultArray = new TConstantUnion[maxObjectSize];
2895 for (size_t i = 0; i < maxObjectSize; i++)
2896 {
2897 switch (basicType)
2898 {
2899 case EbtFloat:
2900 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2901 unionArrays[1][i].getFConst());
2902 break;
2903 case EbtInt:
2904 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2905 unionArrays[1][i].getIConst());
2906 break;
2907 case EbtUInt:
2908 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2909 unionArrays[1][i].getUConst());
2910 break;
2911 default:
2912 UNREACHABLE();
2913 break;
2914 }
2915 }
2916 break;
2917 }
2918
2919 case EOpLessThanEqualComponentWise:
2920 {
2921 resultArray = new TConstantUnion[maxObjectSize];
2922 for (size_t i = 0; i < maxObjectSize; i++)
2923 {
2924 switch (basicType)
2925 {
2926 case EbtFloat:
2927 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2928 unionArrays[1][i].getFConst());
2929 break;
2930 case EbtInt:
2931 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2932 unionArrays[1][i].getIConst());
2933 break;
2934 case EbtUInt:
2935 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2936 unionArrays[1][i].getUConst());
2937 break;
2938 default:
2939 UNREACHABLE();
2940 break;
2941 }
2942 }
2943 break;
2944 }
2945
2946 case EOpGreaterThanComponentWise:
2947 {
2948 resultArray = new TConstantUnion[maxObjectSize];
2949 for (size_t i = 0; i < maxObjectSize; i++)
2950 {
2951 switch (basicType)
2952 {
2953 case EbtFloat:
2954 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2955 unionArrays[1][i].getFConst());
2956 break;
2957 case EbtInt:
2958 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2959 unionArrays[1][i].getIConst());
2960 break;
2961 case EbtUInt:
2962 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2963 unionArrays[1][i].getUConst());
2964 break;
2965 default:
2966 UNREACHABLE();
2967 break;
2968 }
2969 }
2970 break;
2971 }
2972 case EOpGreaterThanEqualComponentWise:
2973 {
2974 resultArray = new TConstantUnion[maxObjectSize];
2975 for (size_t i = 0; i < maxObjectSize; i++)
2976 {
2977 switch (basicType)
2978 {
2979 case EbtFloat:
2980 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2981 unionArrays[1][i].getFConst());
2982 break;
2983 case EbtInt:
2984 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2985 unionArrays[1][i].getIConst());
2986 break;
2987 case EbtUInt:
2988 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2989 unionArrays[1][i].getUConst());
2990 break;
2991 default:
2992 UNREACHABLE();
2993 break;
2994 }
2995 }
2996 }
2997 break;
2998
2999 case EOpEqualComponentWise:
3000 {
3001 resultArray = new TConstantUnion[maxObjectSize];
3002 for (size_t i = 0; i < maxObjectSize; i++)
3003 {
3004 switch (basicType)
3005 {
3006 case EbtFloat:
3007 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
3008 unionArrays[1][i].getFConst());
3009 break;
3010 case EbtInt:
3011 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
3012 unionArrays[1][i].getIConst());
3013 break;
3014 case EbtUInt:
3015 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
3016 unionArrays[1][i].getUConst());
3017 break;
3018 case EbtBool:
3019 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
3020 unionArrays[1][i].getBConst());
3021 break;
3022 default:
3023 UNREACHABLE();
3024 break;
3025 }
3026 }
3027 break;
3028 }
3029
3030 case EOpNotEqualComponentWise:
3031 {
3032 resultArray = new TConstantUnion[maxObjectSize];
3033 for (size_t i = 0; i < maxObjectSize; i++)
3034 {
3035 switch (basicType)
3036 {
3037 case EbtFloat:
3038 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
3039 unionArrays[1][i].getFConst());
3040 break;
3041 case EbtInt:
3042 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3043 unionArrays[1][i].getIConst());
3044 break;
3045 case EbtUInt:
3046 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3047 unionArrays[1][i].getUConst());
3048 break;
3049 case EbtBool:
3050 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3051 unionArrays[1][i].getBConst());
3052 break;
3053 default:
3054 UNREACHABLE();
3055 break;
3056 }
3057 }
3058 break;
3059 }
3060
3061 case EOpDistance:
3062 {
3063 ASSERT(basicType == EbtFloat);
3064 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3065 resultArray = new TConstantUnion();
3066 for (size_t i = 0; i < maxObjectSize; i++)
3067 {
3068 float x = unionArrays[0][i].getFConst();
3069 float y = unionArrays[1][i].getFConst();
3070 distanceArray[i].setFConst(x - y);
3071 }
3072 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3073 break;
3074 }
3075
3076 case EOpDot:
3077 ASSERT(basicType == EbtFloat);
3078 resultArray = new TConstantUnion();
3079 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3080 break;
3081
3082 case EOpCross:
3083 {
3084 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3085 resultArray = new TConstantUnion[maxObjectSize];
3086 float x0 = unionArrays[0][0].getFConst();
3087 float x1 = unionArrays[0][1].getFConst();
3088 float x2 = unionArrays[0][2].getFConst();
3089 float y0 = unionArrays[1][0].getFConst();
3090 float y1 = unionArrays[1][1].getFConst();
3091 float y2 = unionArrays[1][2].getFConst();
3092 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3093 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3094 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3095 break;
3096 }
3097
3098 case EOpReflect:
3099 {
3100 ASSERT(basicType == EbtFloat);
3101 // genType reflect (genType I, genType N) :
3102 // For the incident vector I and surface orientation N, returns the reflection
3103 // direction:
3104 // I - 2 * dot(N, I) * N.
3105 resultArray = new TConstantUnion[maxObjectSize];
3106 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3107 for (size_t i = 0; i < maxObjectSize; i++)
3108 {
3109 float result = unionArrays[0][i].getFConst() -
3110 2.0f * dotProduct * unionArrays[1][i].getFConst();
3111 resultArray[i].setFConst(result);
3112 }
3113 break;
3114 }
3115
3116 case EOpMulMatrixComponentWise:
3117 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003118 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3119 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003120 // Perform component-wise matrix multiplication.
3121 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003122 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003123 angle::Matrix<float> result =
3124 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3125 SetUnionArrayFromMatrix(result, resultArray);
3126 break;
3127 }
3128
3129 case EOpOuterProduct:
3130 {
3131 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003132 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3133 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003134 resultArray = new TConstantUnion[numRows * numCols];
3135 angle::Matrix<float> result =
3136 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3137 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3138 SetUnionArrayFromMatrix(result, resultArray);
3139 break;
3140 }
3141
3142 case EOpClamp:
3143 {
3144 resultArray = new TConstantUnion[maxObjectSize];
3145 for (size_t i = 0; i < maxObjectSize; i++)
3146 {
3147 switch (basicType)
3148 {
3149 case EbtFloat:
3150 {
3151 float x = unionArrays[0][i].getFConst();
3152 float min = unionArrays[1][i].getFConst();
3153 float max = unionArrays[2][i].getFConst();
3154 // Results are undefined if min > max.
3155 if (min > max)
3156 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3157 &resultArray[i]);
3158 else
3159 resultArray[i].setFConst(gl::clamp(x, min, max));
3160 break;
3161 }
3162
3163 case EbtInt:
3164 {
3165 int x = unionArrays[0][i].getIConst();
3166 int min = unionArrays[1][i].getIConst();
3167 int max = unionArrays[2][i].getIConst();
3168 // Results are undefined if min > max.
3169 if (min > max)
3170 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3171 &resultArray[i]);
3172 else
3173 resultArray[i].setIConst(gl::clamp(x, min, max));
3174 break;
3175 }
3176 case EbtUInt:
3177 {
3178 unsigned int x = unionArrays[0][i].getUConst();
3179 unsigned int min = unionArrays[1][i].getUConst();
3180 unsigned int max = unionArrays[2][i].getUConst();
3181 // Results are undefined if min > max.
3182 if (min > max)
3183 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3184 &resultArray[i]);
3185 else
3186 resultArray[i].setUConst(gl::clamp(x, min, max));
3187 break;
3188 }
3189 default:
3190 UNREACHABLE();
3191 break;
3192 }
3193 }
3194 break;
3195 }
3196
3197 case EOpMix:
3198 {
3199 ASSERT(basicType == EbtFloat);
3200 resultArray = new TConstantUnion[maxObjectSize];
3201 for (size_t i = 0; i < maxObjectSize; i++)
3202 {
3203 float x = unionArrays[0][i].getFConst();
3204 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003205 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003206 if (type == EbtFloat)
3207 {
3208 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3209 float a = unionArrays[2][i].getFConst();
3210 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3211 }
3212 else // 3rd parameter is EbtBool
3213 {
3214 ASSERT(type == EbtBool);
3215 // Selects which vector each returned component comes from.
3216 // For a component of a that is false, the corresponding component of x is
3217 // returned.
3218 // For a component of a that is true, the corresponding component of y is
3219 // returned.
3220 bool a = unionArrays[2][i].getBConst();
3221 resultArray[i].setFConst(a ? y : x);
3222 }
3223 }
3224 break;
3225 }
3226
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02003227 case EOpSmoothstep:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003228 {
3229 ASSERT(basicType == EbtFloat);
3230 resultArray = new TConstantUnion[maxObjectSize];
3231 for (size_t i = 0; i < maxObjectSize; i++)
3232 {
3233 float edge0 = unionArrays[0][i].getFConst();
3234 float edge1 = unionArrays[1][i].getFConst();
3235 float x = unionArrays[2][i].getFConst();
3236 // Results are undefined if edge0 >= edge1.
3237 if (edge0 >= edge1)
3238 {
3239 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3240 }
3241 else
3242 {
3243 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3244 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3245 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3246 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3247 }
3248 }
3249 break;
3250 }
3251
Olli Etuaho74da73f2017-02-01 15:37:48 +00003252 case EOpLdexp:
3253 {
3254 resultArray = new TConstantUnion[maxObjectSize];
3255 for (size_t i = 0; i < maxObjectSize; i++)
3256 {
3257 float x = unionArrays[0][i].getFConst();
3258 int exp = unionArrays[1][i].getIConst();
3259 if (exp > 128)
3260 {
3261 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3262 }
3263 else
3264 {
3265 resultArray[i].setFConst(gl::Ldexp(x, exp));
3266 }
3267 }
3268 break;
3269 }
3270
Jamie Madille72595b2017-06-06 15:12:26 -04003271 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003272 {
3273 ASSERT(basicType == EbtFloat);
3274 // genType faceforward(genType N, genType I, genType Nref) :
3275 // If dot(Nref, I) < 0 return N, otherwise return -N.
3276 resultArray = new TConstantUnion[maxObjectSize];
3277 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3278 for (size_t i = 0; i < maxObjectSize; i++)
3279 {
3280 if (dotProduct < 0)
3281 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3282 else
3283 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3284 }
3285 break;
3286 }
3287
3288 case EOpRefract:
3289 {
3290 ASSERT(basicType == EbtFloat);
3291 // genType refract(genType I, genType N, float eta) :
3292 // For the incident vector I and surface normal N, and the ratio of indices of
3293 // refraction eta,
3294 // return the refraction vector. The result is computed by
3295 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3296 // if (k < 0.0)
3297 // return genType(0.0)
3298 // else
3299 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3300 resultArray = new TConstantUnion[maxObjectSize];
3301 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3302 for (size_t i = 0; i < maxObjectSize; i++)
3303 {
3304 float eta = unionArrays[2][i].getFConst();
3305 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3306 if (k < 0.0f)
3307 resultArray[i].setFConst(0.0f);
3308 else
3309 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3310 (eta * dotProduct + sqrtf(k)) *
3311 unionArrays[1][i].getFConst());
3312 }
3313 break;
3314 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003315 case EOpBitfieldExtract:
3316 {
3317 resultArray = new TConstantUnion[maxObjectSize];
3318 for (size_t i = 0; i < maxObjectSize; ++i)
3319 {
3320 int offset = unionArrays[1][0].getIConst();
3321 int bits = unionArrays[2][0].getIConst();
3322 if (bits == 0)
3323 {
3324 if (aggregate->getBasicType() == EbtInt)
3325 {
3326 resultArray[i].setIConst(0);
3327 }
3328 else
3329 {
3330 ASSERT(aggregate->getBasicType() == EbtUInt);
3331 resultArray[i].setUConst(0);
3332 }
3333 }
3334 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3335 {
3336 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3337 &resultArray[i]);
3338 }
3339 else
3340 {
3341 // bits can be 32 here, so we need to avoid bit shift overflow.
3342 uint32_t maskMsb = 1u << (bits - 1);
3343 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3344 if (aggregate->getBasicType() == EbtInt)
3345 {
3346 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3347 uint32_t resultUnsigned = (value & mask) >> offset;
3348 if ((resultUnsigned & maskMsb) != 0)
3349 {
3350 // The most significant bits (from bits+1 to the most significant bit)
3351 // should be set to 1.
3352 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3353 resultUnsigned |= higherBitsMask;
3354 }
3355 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3356 }
3357 else
3358 {
3359 ASSERT(aggregate->getBasicType() == EbtUInt);
3360 uint32_t value = unionArrays[0][i].getUConst();
3361 resultArray[i].setUConst((value & mask) >> offset);
3362 }
3363 }
3364 }
3365 break;
3366 }
3367 case EOpBitfieldInsert:
3368 {
3369 resultArray = new TConstantUnion[maxObjectSize];
3370 for (size_t i = 0; i < maxObjectSize; ++i)
3371 {
3372 int offset = unionArrays[2][0].getIConst();
3373 int bits = unionArrays[3][0].getIConst();
3374 if (bits == 0)
3375 {
3376 if (aggregate->getBasicType() == EbtInt)
3377 {
3378 int32_t base = unionArrays[0][i].getIConst();
3379 resultArray[i].setIConst(base);
3380 }
3381 else
3382 {
3383 ASSERT(aggregate->getBasicType() == EbtUInt);
3384 uint32_t base = unionArrays[0][i].getUConst();
3385 resultArray[i].setUConst(base);
3386 }
3387 }
3388 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3389 {
3390 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3391 &resultArray[i]);
3392 }
3393 else
3394 {
3395 // bits can be 32 here, so we need to avoid bit shift overflow.
3396 uint32_t maskMsb = 1u << (bits - 1);
3397 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3398 uint32_t baseMask = ~insertMask;
3399 if (aggregate->getBasicType() == EbtInt)
3400 {
3401 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3402 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3403 uint32_t resultUnsigned =
3404 (base & baseMask) | ((insert << offset) & insertMask);
3405 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3406 }
3407 else
3408 {
3409 ASSERT(aggregate->getBasicType() == EbtUInt);
3410 uint32_t base = unionArrays[0][i].getUConst();
3411 uint32_t insert = unionArrays[1][i].getUConst();
3412 resultArray[i].setUConst((base & baseMask) |
3413 ((insert << offset) & insertMask));
3414 }
3415 }
3416 }
3417 break;
3418 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003419
3420 default:
3421 UNREACHABLE();
3422 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303423 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003424 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303425}
3426
Jamie Madill45bcc782016-11-07 13:58:48 -05003427} // namespace sh