blob: dca3bc74341230f207b2f54034facc7220bd756d [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:
154 case EOpSmoothStep:
155 case EOpLdexp:
156 case EOpMulMatrixComponentWise:
157 case EOpOuterProduct:
158 case EOpEqualComponentWise:
159 case EOpNotEqualComponentWise:
160 case EOpLessThanComponentWise:
161 case EOpLessThanEqualComponentWise:
162 case EOpGreaterThanComponentWise:
163 case EOpGreaterThanEqualComponentWise:
164 case EOpDistance:
165 case EOpDot:
166 case EOpCross:
167 case EOpFaceforward:
168 case EOpReflect:
169 case EOpRefract:
170 case EOpBitfieldExtract:
171 case EOpBitfieldInsert:
172 return true;
173 default:
174 return false;
175 }
176}
177
Jamie Madillb1a85f42014-08-19 15:23:24 -0400178} // namespace anonymous
179
Jamie Madillb1a85f42014-08-19 15:23:24 -0400180////////////////////////////////////////////////////////////////
181//
182// Member functions of the nodes used for building the tree.
183//
184////////////////////////////////////////////////////////////////
185
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200186TIntermExpression::TIntermExpression(const TType &t) : TIntermTyped(), mType(t)
187{
188}
189
190void TIntermExpression::setTypePreservePrecision(const TType &t)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300191{
192 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500193 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300194 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
195 mType.setPrecision(precision);
196}
197
Jamie Madillb1a85f42014-08-19 15:23:24 -0400198#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500199 if (node == original) \
200 { \
201 node = static_cast<type *>(replacement); \
202 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400203 }
204
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500205bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400206{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300207 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400208 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
209 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
210 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100211 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400212 return false;
213}
214
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500215bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400216{
217 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
218 return false;
219}
220
Olli Etuahob6fa0432016-09-28 16:28:05 +0100221bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
222{
223 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
224 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
225 return false;
226}
227
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500228bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400229{
230 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
231 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
232 return false;
233}
234
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500235bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400236{
Olli Etuahoa2234302016-08-31 12:05:39 +0300237 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400238 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
239 return false;
240}
241
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000242bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
243{
244 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
245 return false;
246}
247
Olli Etuaho336b1472016-10-05 16:37:55 +0100248bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
249{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000250 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100251 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
252 return false;
253}
254
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500255bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400256{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100257 return replaceChildNodeInternal(original, replacement);
258}
259
260bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
261{
262 return replaceChildNodeInternal(original, replacement);
263}
264
Olli Etuaho16c745a2017-01-16 17:02:27 +0000265bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
266{
267 return replaceChildNodeInternal(original, replacement);
268}
269
Olli Etuaho13389b62016-10-16 11:48:18 +0100270bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
271{
272 return replaceChildNodeInternal(original, replacement);
273}
274
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100275bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
276{
277 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400278 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100279 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400280 }
281 return false;
282}
283
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100284bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
285 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300286{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100287 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300288 {
289 if (*it == original)
290 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100291 it = getSequence()->erase(it);
292 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300293 return true;
294 }
295 }
296 return false;
297}
298
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100299bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
300 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300301{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100302 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300303 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300304 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300305 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100306 auto it = getSequence()->begin() + position;
307 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300308 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300309}
310
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200311TIntermSymbol::TIntermSymbol(const TVariable *variable) : TIntermTyped(), mVariable(variable)
Olli Etuaho195be942017-12-04 23:40:14 +0200312{
Olli Etuaho195be942017-12-04 23:40:14 +0200313}
314
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200315bool TIntermSymbol::hasConstantValue() const
316{
317 return variable().getConstPointer() != nullptr;
318}
319
320const TConstantUnion *TIntermSymbol::getConstantValue() const
321{
322 return variable().getConstPointer();
323}
324
Olli Etuahob6af22b2017-12-15 14:05:44 +0200325const TSymbolUniqueId &TIntermSymbol::uniqueId() const
326{
327 return mVariable->uniqueId();
328}
329
Olli Etuahofbb1c792018-01-19 16:26:59 +0200330ImmutableString TIntermSymbol::getName() const
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200331{
332 return mVariable->name();
333}
334
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200335const TType &TIntermSymbol::getType() const
336{
337 return mVariable->getType();
338}
339
Olli Etuahofe486322017-03-21 09:30:54 +0000340TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
341 TIntermSequence *arguments)
342{
Olli Etuaho0c371002017-12-13 17:00:25 +0400343 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000344}
345
Olli Etuaho0c371002017-12-13 17:00:25 +0400346TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
347 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000348{
Olli Etuaho0c371002017-12-13 17:00:25 +0400349 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000350}
351
352TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
353 TIntermSequence *arguments)
354{
355 TIntermAggregate *callNode =
Olli Etuaho0c371002017-12-13 17:00:25 +0400356 new TIntermAggregate(&func, func.getReturnType(), EOpCallBuiltInFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000357 // Note that name needs to be set before texture function type is determined.
358 callNode->setBuiltInFunctionPrecision();
359 return callNode;
360}
361
362TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000363 TIntermSequence *arguments)
364{
Olli Etuaho0c371002017-12-13 17:00:25 +0400365 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000366}
367
Olli Etuaho68981eb2018-01-23 17:46:12 +0200368TIntermAggregate *TIntermAggregate::Create(const TFunction &func,
Olli Etuahofe486322017-03-21 09:30:54 +0000369 TOperator op,
370 TIntermSequence *arguments)
371{
Olli Etuahofe486322017-03-21 09:30:54 +0000372 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400373 ASSERT(op != EOpCallInternalRawFunction); // Should use CreateRawFunctionCall
Olli Etuahofe486322017-03-21 09:30:54 +0000374 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400375 ASSERT(op != EOpConstruct); // Should use CreateConstructor
Olli Etuaho68981eb2018-01-23 17:46:12 +0200376 return new TIntermAggregate(&func, func.getReturnType(), op, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000377}
378
Olli Etuaho0c371002017-12-13 17:00:25 +0400379TIntermAggregate::TIntermAggregate(const TFunction *func,
380 const TType &type,
381 TOperator op,
382 TIntermSequence *arguments)
383 : TIntermOperator(op),
384 mUseEmulatedFunction(false),
385 mGotPrecisionFromChildren(false),
386 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800387{
388 if (arguments != nullptr)
389 {
390 mArguments.swap(*arguments);
391 }
Olli Etuaho1bb85282017-12-14 13:39:53 +0200392 ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800393 setTypePrecisionAndQualifier(type);
394}
395
396void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
397{
398 setType(type);
399 mType.setQualifier(EvqTemporary);
400 if (!isFunctionCall())
401 {
402 if (isConstructor())
403 {
404 // Structs should not be precision qualified, the individual members may be.
405 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300406 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800407 {
408 setPrecisionFromChildren();
409 }
410 }
411 else
412 {
413 setPrecisionForBuiltInOp();
414 }
415 if (areChildrenConstQualified())
416 {
417 mType.setQualifier(EvqConst);
418 }
419 }
420}
421
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200422bool TIntermAggregate::areChildrenConstQualified()
423{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800424 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200425 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800426 TIntermTyped *typedArg = arg->getAsTyped();
427 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200428 {
429 return false;
430 }
431 }
432 return true;
433}
434
Olli Etuahod2a67b92014-10-21 16:42:57 +0300435void TIntermAggregate::setPrecisionFromChildren()
436{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300437 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300438 if (getBasicType() == EbtBool)
439 {
440 mType.setPrecision(EbpUndefined);
441 return;
442 }
443
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500444 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800445 TIntermSequence::iterator childIter = mArguments.begin();
446 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300447 {
448 TIntermTyped *typed = (*childIter)->getAsTyped();
449 if (typed)
450 precision = GetHigherPrecision(typed->getPrecision(), precision);
451 ++childIter;
452 }
453 mType.setPrecision(precision);
454}
455
Olli Etuaho9250cb22017-01-21 10:51:27 +0000456void TIntermAggregate::setPrecisionForBuiltInOp()
457{
458 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800459 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000460 if (!setPrecisionForSpecialBuiltInOp())
461 {
462 setPrecisionFromChildren();
463 }
464}
465
466bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
467{
468 switch (mOp)
469 {
470 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800471 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
472 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000473 return true;
474 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800475 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
476 mArguments[1]->getAsTyped()->getPrecision()));
477 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000478 return true;
479 case EOpUaddCarry:
480 case EOpUsubBorrow:
481 mType.setPrecision(EbpHigh);
482 return true;
483 default:
484 return false;
485 }
486}
487
Olli Etuahod2a67b92014-10-21 16:42:57 +0300488void TIntermAggregate::setBuiltInFunctionPrecision()
489{
490 // All built-ins returning bool should be handled as ops, not functions.
491 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800492 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300493
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800494 TPrecision precision = EbpUndefined;
495 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300496 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800497 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300498 // ESSL spec section 8: texture functions get their precision from the sampler.
499 if (typed && IsSampler(typed->getBasicType()))
500 {
501 precision = typed->getPrecision();
502 break;
503 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300504 }
505 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
506 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahofbb1c792018-01-19 16:26:59 +0200507 if (mFunction->name() == "textureSize")
Olli Etuahod2a67b92014-10-21 16:42:57 +0300508 mType.setPrecision(EbpHigh);
509 else
510 mType.setPrecision(precision);
511}
512
Olli Etuaho0c371002017-12-13 17:00:25 +0400513const char *TIntermAggregate::functionName() const
514{
515 ASSERT(!isConstructor());
516 switch (mOp)
517 {
518 case EOpCallInternalRawFunction:
519 case EOpCallBuiltInFunction:
520 case EOpCallFunctionInAST:
Olli Etuahofbb1c792018-01-19 16:26:59 +0200521 return mFunction->name().data();
Olli Etuaho0c371002017-12-13 17:00:25 +0400522 default:
523 return GetOperatorString(mOp);
524 }
525}
526
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200527bool TIntermAggregate::hasConstantValue() const
528{
529 if (!isConstructor())
530 {
531 return false;
532 }
533 for (TIntermNode *constructorArg : mArguments)
534 {
535 if (!constructorArg->getAsTyped()->hasConstantValue())
536 {
537 return false;
538 }
539 }
540 return true;
541}
542
543const TConstantUnion *TIntermAggregate::getConstantValue() const
544{
545 if (!hasConstantValue())
546 {
547 return nullptr;
548 }
549 ASSERT(isConstructor());
550 ASSERT(mArguments.size() > 0u);
551
552 TConstantUnion *constArray = nullptr;
553 if (isArray())
554 {
555 size_t elementSize = mArguments.front()->getAsTyped()->getType().getObjectSize();
556 constArray = new TConstantUnion[elementSize * getOutermostArraySize()];
557
558 size_t elementOffset = 0u;
559 for (TIntermNode *constructorArg : mArguments)
560 {
561 const TConstantUnion *elementConstArray =
562 constructorArg->getAsTyped()->getConstantValue();
563 ASSERT(elementConstArray);
564 size_t elementSizeBytes = sizeof(TConstantUnion) * elementSize;
565 memcpy(static_cast<void *>(&constArray[elementOffset]),
566 static_cast<const void *>(elementConstArray), elementSizeBytes);
567 elementOffset += elementSize;
568 }
569 return constArray;
570 }
571
572 size_t resultSize = getType().getObjectSize();
573 constArray = new TConstantUnion[resultSize];
574 TBasicType basicType = getBasicType();
575
576 size_t resultIndex = 0u;
577
578 if (mArguments.size() == 1u)
579 {
580 TIntermNode *argument = mArguments.front();
581 TIntermTyped *argumentTyped = argument->getAsTyped();
582 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
583 // Check the special case of constructing a matrix diagonal from a single scalar,
584 // or a vector from a single scalar.
585 if (argumentTyped->getType().getObjectSize() == 1u)
586 {
587 if (isMatrix())
588 {
589 int resultCols = getType().getCols();
590 int resultRows = getType().getRows();
591 for (int col = 0; col < resultCols; ++col)
592 {
593 for (int row = 0; row < resultRows; ++row)
594 {
595 if (col == row)
596 {
597 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
598 }
599 else
600 {
601 constArray[resultIndex].setFConst(0.0f);
602 }
603 ++resultIndex;
604 }
605 }
606 }
607 else
608 {
609 while (resultIndex < resultSize)
610 {
611 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
612 ++resultIndex;
613 }
614 }
615 ASSERT(resultIndex == resultSize);
616 return constArray;
617 }
618 else if (isMatrix() && argumentTyped->isMatrix())
619 {
620 // The special case of constructing a matrix from a matrix.
621 int argumentCols = argumentTyped->getType().getCols();
622 int argumentRows = argumentTyped->getType().getRows();
623 int resultCols = getType().getCols();
624 int resultRows = getType().getRows();
625 for (int col = 0; col < resultCols; ++col)
626 {
627 for (int row = 0; row < resultRows; ++row)
628 {
629 if (col < argumentCols && row < argumentRows)
630 {
631 constArray[resultIndex].cast(
632 basicType, argumentConstantValue[col * argumentRows + row]);
633 }
634 else if (col == row)
635 {
636 constArray[resultIndex].setFConst(1.0f);
637 }
638 else
639 {
640 constArray[resultIndex].setFConst(0.0f);
641 }
642 ++resultIndex;
643 }
644 }
645 ASSERT(resultIndex == resultSize);
646 return constArray;
647 }
648 }
649
650 for (TIntermNode *argument : mArguments)
651 {
652 TIntermTyped *argumentTyped = argument->getAsTyped();
653 size_t argumentSize = argumentTyped->getType().getObjectSize();
654 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
655 for (size_t i = 0u; i < argumentSize; ++i)
656 {
657 if (resultIndex >= resultSize)
658 break;
659 constArray[resultIndex].cast(basicType, argumentConstantValue[i]);
660 ++resultIndex;
661 }
662 }
663 ASSERT(resultIndex == resultSize);
664 return constArray;
665}
666
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300667bool TIntermAggregate::hasSideEffects() const
668{
Olli Etuahoea78d2b2018-01-09 12:55:27 +0200669 if (getQualifier() == EvqConst)
670 {
671 return false;
672 }
673 bool calledFunctionHasNoSideEffects =
674 isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects();
675 if (calledFunctionHasNoSideEffects || isConstructor())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300676 {
677 for (TIntermNode *arg : mArguments)
678 {
679 if (arg->getAsTyped()->hasSideEffects())
680 {
681 return true;
682 }
683 }
684 return false;
685 }
686 // Conservatively assume most aggregate operators have side-effects
687 return true;
688}
689
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100690void TIntermBlock::appendStatement(TIntermNode *statement)
691{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300692 // Declaration nodes with no children can appear if it was an empty declaration or if all the
693 // declarators just added constants to the symbol table instead of generating code. We still
694 // need to add the declaration to the AST in that case because it might be relevant to the
695 // validity of switch/case.
696 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100697 {
698 mStatements.push_back(statement);
699 }
700}
701
Olli Etuaho16c745a2017-01-16 17:02:27 +0000702void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
703{
704 ASSERT(parameter != nullptr);
705 mParameters.push_back(parameter);
706}
707
Olli Etuaho13389b62016-10-16 11:48:18 +0100708void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
709{
710 ASSERT(declarator != nullptr);
711 ASSERT(declarator->getAsSymbolNode() != nullptr ||
712 (declarator->getAsBinaryNode() != nullptr &&
713 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
714 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300715 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100716 mDeclarators.push_back(declarator);
717}
718
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300719bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
720{
721 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
722 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
723 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
724 return false;
725}
726
Olli Etuaho57961272016-09-14 13:57:46 +0300727bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400728{
729 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100730 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
731 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400732 return false;
733}
734
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500735bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200736{
737 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100738 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300739 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200740 return false;
741}
742
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500743bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200744{
745 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
746 return false;
747}
748
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200749TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode()
Olli Etuahod7a25242015-08-18 13:49:45 +0300750{
751 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
752 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200753 // We need to manually copy any fields of TIntermNode.
Olli Etuahod7a25242015-08-18 13:49:45 +0300754 mLine = node.mLine;
755}
756
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200757bool TIntermTyped::hasConstantValue() const
Olli Etuahod4f4c112016-04-15 15:11:24 +0300758{
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200759 return false;
760}
761
762const TConstantUnion *TIntermTyped::getConstantValue() const
763{
764 return nullptr;
Olli Etuahod4f4c112016-04-15 15:11:24 +0300765}
766
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200767TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node)
768 : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300769{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200770 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300771}
772
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200773TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200774 : TIntermTyped(), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100775{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200776 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100777}
778
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200779const TType &TIntermFunctionPrototype::getType() const
780{
781 return mFunction->getReturnType();
782}
783
Olli Etuahod7a25242015-08-18 13:49:45 +0300784TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
785 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300786 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100787 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400788 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300789{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800790 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300791 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800792 TIntermTyped *typedArg = arg->getAsTyped();
793 ASSERT(typedArg != nullptr);
794 TIntermTyped *argCopy = typedArg->deepCopy();
795 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300796 }
797}
798
Olli Etuahofe486322017-03-21 09:30:54 +0000799TIntermAggregate *TIntermAggregate::shallowCopy() const
800{
801 TIntermSequence *copySeq = new TIntermSequence();
802 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400803 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000804 copyNode->setLine(mLine);
805 return copyNode;
806}
807
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200808TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermExpression(node)
Olli Etuahob6fa0432016-09-28 16:28:05 +0100809{
810 TIntermTyped *operandCopy = node.mOperand->deepCopy();
811 ASSERT(operandCopy != nullptr);
812 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000813 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100814}
815
Olli Etuahod7a25242015-08-18 13:49:45 +0300816TIntermBinary::TIntermBinary(const TIntermBinary &node)
817 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
818{
819 TIntermTyped *leftCopy = node.mLeft->deepCopy();
820 TIntermTyped *rightCopy = node.mRight->deepCopy();
821 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
822 mLeft = leftCopy;
823 mRight = rightCopy;
824}
825
826TIntermUnary::TIntermUnary(const TIntermUnary &node)
827 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
828{
829 TIntermTyped *operandCopy = node.mOperand->deepCopy();
830 ASSERT(operandCopy != nullptr);
831 mOperand = operandCopy;
832}
833
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200834TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300835{
Olli Etuahod7a25242015-08-18 13:49:45 +0300836 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300837 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
838 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300839 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300840 mCondition = conditionCopy;
841 mTrueExpression = trueCopy;
842 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300843}
844
Jamie Madillb1a85f42014-08-19 15:23:24 -0400845bool TIntermOperator::isAssignment() const
846{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300847 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400848}
849
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300850bool TIntermOperator::isMultiplication() const
851{
852 switch (mOp)
853 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500854 case EOpMul:
855 case EOpMatrixTimesMatrix:
856 case EOpMatrixTimesVector:
857 case EOpMatrixTimesScalar:
858 case EOpVectorTimesMatrix:
859 case EOpVectorTimesScalar:
860 return true;
861 default:
862 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300863 }
864}
865
Jamie Madillb1a85f42014-08-19 15:23:24 -0400866bool TIntermOperator::isConstructor() const
867{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300868 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400869}
870
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800871bool TIntermOperator::isFunctionCall() const
872{
873 switch (mOp)
874 {
875 case EOpCallFunctionInAST:
876 case EOpCallBuiltInFunction:
877 case EOpCallInternalRawFunction:
878 return true;
879 default:
880 return false;
881 }
882}
883
Olli Etuaho1dded802016-08-18 18:13:13 +0300884TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
885{
886 if (left.isMatrix())
887 {
888 if (right.isMatrix())
889 {
890 return EOpMatrixTimesMatrix;
891 }
892 else
893 {
894 if (right.isVector())
895 {
896 return EOpMatrixTimesVector;
897 }
898 else
899 {
900 return EOpMatrixTimesScalar;
901 }
902 }
903 }
904 else
905 {
906 if (right.isMatrix())
907 {
908 if (left.isVector())
909 {
910 return EOpVectorTimesMatrix;
911 }
912 else
913 {
914 return EOpMatrixTimesScalar;
915 }
916 }
917 else
918 {
919 // Neither operand is a matrix.
920 if (left.isVector() == right.isVector())
921 {
922 // Leave as component product.
923 return EOpMul;
924 }
925 else
926 {
927 return EOpVectorTimesScalar;
928 }
929 }
930 }
931}
932
933TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
934{
935 if (left.isMatrix())
936 {
937 if (right.isMatrix())
938 {
939 return EOpMatrixTimesMatrixAssign;
940 }
941 else
942 {
943 // right should be scalar, but this may not be validated yet.
944 return EOpMatrixTimesScalarAssign;
945 }
946 }
947 else
948 {
949 if (right.isMatrix())
950 {
951 // Left should be a vector, but this may not be validated yet.
952 return EOpVectorTimesMatrixAssign;
953 }
954 else
955 {
956 // Neither operand is a matrix.
957 if (left.isVector() == right.isVector())
958 {
959 // Leave as component product.
960 return EOpMulAssign;
961 }
962 else
963 {
964 // left should be vector and right should be scalar, but this may not be validated
965 // yet.
966 return EOpVectorTimesScalarAssign;
967 }
968 }
969 }
970}
971
Jamie Madillb1a85f42014-08-19 15:23:24 -0400972//
973// Make sure the type of a unary operator is appropriate for its
974// combination of operation and operand type.
975//
Olli Etuahoa2234302016-08-31 12:05:39 +0300976void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400977{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300978 if (mOp == EOpArrayLength)
979 {
980 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
981 setType(TType(EbtInt, EbpUndefined, EvqConst));
982 return;
983 }
984
Olli Etuahoa2234302016-08-31 12:05:39 +0300985 TQualifier resultQualifier = EvqTemporary;
986 if (mOperand->getQualifier() == EvqConst)
987 resultQualifier = EvqConst;
988
989 unsigned char operandPrimarySize =
990 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400991 switch (mOp)
992 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300993 case EOpFloatBitsToInt:
994 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
995 break;
996 case EOpFloatBitsToUint:
997 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
998 break;
999 case EOpIntBitsToFloat:
1000 case EOpUintBitsToFloat:
1001 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
1002 break;
1003 case EOpPackSnorm2x16:
1004 case EOpPackUnorm2x16:
1005 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001006 case EOpPackUnorm4x8:
1007 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +03001008 setType(TType(EbtUInt, EbpHigh, resultQualifier));
1009 break;
1010 case EOpUnpackSnorm2x16:
1011 case EOpUnpackUnorm2x16:
1012 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
1013 break;
1014 case EOpUnpackHalf2x16:
1015 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
1016 break;
Olli Etuaho25aef452017-01-29 16:15:44 -08001017 case EOpUnpackUnorm4x8:
1018 case EOpUnpackSnorm4x8:
1019 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
1020 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001021 case EOpAny:
1022 case EOpAll:
1023 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1024 break;
1025 case EOpLength:
1026 case EOpDeterminant:
1027 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
1028 break;
1029 case EOpTranspose:
1030 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
1031 static_cast<unsigned char>(mOperand->getType().getRows()),
1032 static_cast<unsigned char>(mOperand->getType().getCols())));
1033 break;
1034 case EOpIsInf:
1035 case EOpIsNan:
1036 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
1037 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001038 case EOpBitfieldReverse:
1039 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
1040 break;
1041 case EOpBitCount:
1042 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1043 break;
1044 case EOpFindLSB:
1045 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1046 break;
1047 case EOpFindMSB:
1048 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1049 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001050 default:
1051 setType(mOperand->getType());
1052 mType.setQualifier(resultQualifier);
1053 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001054 }
Olli Etuahoa2234302016-08-31 12:05:39 +03001055}
Jamie Madillb1a85f42014-08-19 15:23:24 -04001056
Olli Etuahob6fa0432016-09-28 16:28:05 +01001057TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001058 : TIntermExpression(TType(EbtFloat, EbpUndefined)),
Olli Etuahob6fa0432016-09-28 16:28:05 +01001059 mOperand(operand),
1060 mSwizzleOffsets(swizzleOffsets)
1061{
1062 ASSERT(mSwizzleOffsets.size() <= 4);
1063 promote();
1064}
1065
Olli Etuahoa2234302016-08-31 12:05:39 +03001066TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
1067 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
1068{
1069 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001070}
1071
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001072TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1073 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
1074{
1075 promote();
1076}
1077
Olli Etuaho0e99b7a2018-01-12 12:05:48 +02001078TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left,
1079 TIntermTyped *right,
1080 int shaderVersion)
1081{
1082 TIntermBinary *node = new TIntermBinary(EOpComma, left, right);
1083 node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right));
1084 return node;
1085}
1086
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001087TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1088 : TIntermNode(), mSymbol(symbol)
1089{
1090 ASSERT(symbol);
1091 setLine(line);
1092}
1093
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001094TIntermTernary::TIntermTernary(TIntermTyped *cond,
1095 TIntermTyped *trueExpression,
1096 TIntermTyped *falseExpression)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001097 : TIntermExpression(trueExpression->getType()),
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001098 mCondition(cond),
1099 mTrueExpression(trueExpression),
1100 mFalseExpression(falseExpression)
1101{
1102 getTypePointer()->setQualifier(
1103 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1104}
1105
Olli Etuaho81629262017-04-19 11:56:01 +03001106TIntermLoop::TIntermLoop(TLoopType type,
1107 TIntermNode *init,
1108 TIntermTyped *cond,
1109 TIntermTyped *expr,
1110 TIntermBlock *body)
1111 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1112{
1113 // Declaration nodes with no children can appear if all the declarators just added constants to
1114 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1115 if (mInit && mInit->getAsDeclarationNode() &&
1116 mInit->getAsDeclarationNode()->getSequence()->empty())
1117 {
1118 mInit = nullptr;
1119 }
1120}
1121
Olli Etuaho923ecef2017-10-11 12:01:38 +03001122TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
1123 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
1124{
1125 // Prune empty false blocks so that there won't be unnecessary operations done on it.
1126 if (mFalseBlock && mFalseBlock->getSequence()->empty())
1127 {
1128 mFalseBlock = nullptr;
1129 }
1130}
1131
1132TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
1133 : TIntermNode(), mInit(init), mStatementList(statementList)
1134{
1135 ASSERT(mStatementList);
1136}
1137
1138void TIntermSwitch::setStatementList(TIntermBlock *statementList)
1139{
1140 ASSERT(statementList);
1141 mStatementList = statementList;
1142}
1143
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001144// static
1145TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1146 TIntermTyped *trueExpression,
1147 TIntermTyped *falseExpression)
1148{
1149 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1150 falseExpression->getQualifier() == EvqConst)
1151 {
1152 return EvqConst;
1153 }
1154 return EvqTemporary;
1155}
1156
Olli Etuaho765924f2018-01-04 12:48:36 +02001157TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001158{
1159 if (mCondition->getAsConstantUnion())
1160 {
1161 if (mCondition->getAsConstantUnion()->getBConst(0))
1162 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001163 return mTrueExpression;
1164 }
1165 else
1166 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001167 return mFalseExpression;
1168 }
1169 }
1170 return this;
1171}
1172
Olli Etuahob6fa0432016-09-28 16:28:05 +01001173void TIntermSwizzle::promote()
1174{
1175 TQualifier resultQualifier = EvqTemporary;
1176 if (mOperand->getQualifier() == EvqConst)
1177 resultQualifier = EvqConst;
1178
1179 auto numFields = mSwizzleOffsets.size();
1180 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1181 static_cast<unsigned char>(numFields)));
1182}
1183
1184bool TIntermSwizzle::hasDuplicateOffsets() const
1185{
1186 int offsetCount[4] = {0u, 0u, 0u, 0u};
1187 for (const auto offset : mSwizzleOffsets)
1188 {
1189 offsetCount[offset]++;
1190 if (offsetCount[offset] > 1)
1191 {
1192 return true;
1193 }
1194 }
1195 return false;
1196}
1197
Olli Etuaho09b04a22016-12-15 13:30:26 +00001198bool TIntermSwizzle::offsetsMatch(int offset) const
1199{
1200 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1201}
1202
Olli Etuahob6fa0432016-09-28 16:28:05 +01001203void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1204{
1205 for (const int offset : mSwizzleOffsets)
1206 {
1207 switch (offset)
1208 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001209 case 0:
1210 *out << "x";
1211 break;
1212 case 1:
1213 *out << "y";
1214 break;
1215 case 2:
1216 *out << "z";
1217 break;
1218 case 3:
1219 *out << "w";
1220 break;
1221 default:
1222 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001223 }
1224 }
1225}
1226
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001227TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1228 const TIntermTyped *left,
1229 const TIntermTyped *right)
1230{
1231 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1232 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1233 right->getQualifier() != EvqConst)
1234 {
1235 return EvqTemporary;
1236 }
1237 return EvqConst;
1238}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001239
1240// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001241void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001242{
Olli Etuaho1dded802016-08-18 18:13:13 +03001243 ASSERT(!isMultiplication() ||
1244 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1245
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001246 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1247 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001248 if (mOp == EOpComma)
1249 {
1250 setType(mRight->getType());
1251 return;
1252 }
1253
Jamie Madillb1a85f42014-08-19 15:23:24 -04001254 // Base assumption: just make the type the same as the left
1255 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001256 setType(mLeft->getType());
1257
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001258 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001259 // Binary operations results in temporary variables unless both
1260 // operands are const.
1261 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1262 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001263 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001264 getTypePointer()->setQualifier(EvqTemporary);
1265 }
1266
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001267 // Handle indexing ops.
1268 switch (mOp)
1269 {
1270 case EOpIndexDirect:
1271 case EOpIndexIndirect:
1272 if (mLeft->isArray())
1273 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001274 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001275 }
1276 else if (mLeft->isMatrix())
1277 {
1278 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1279 static_cast<unsigned char>(mLeft->getRows())));
1280 }
1281 else if (mLeft->isVector())
1282 {
1283 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1284 }
1285 else
1286 {
1287 UNREACHABLE();
1288 }
1289 return;
1290 case EOpIndexDirectStruct:
1291 {
1292 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1293 const int i = mRight->getAsConstantUnion()->getIConst(0);
1294 setType(*fields[i]->type());
1295 getTypePointer()->setQualifier(resultQualifier);
1296 return;
1297 }
1298 case EOpIndexDirectInterfaceBlock:
1299 {
1300 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1301 const int i = mRight->getAsConstantUnion()->getIConst(0);
1302 setType(*fields[i]->type());
1303 getTypePointer()->setQualifier(resultQualifier);
1304 return;
1305 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001306 default:
1307 break;
1308 }
1309
1310 ASSERT(mLeft->isArray() == mRight->isArray());
1311
1312 // The result gets promoted to the highest precision.
1313 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1314 getTypePointer()->setPrecision(higherPrecision);
1315
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001316 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001317
1318 //
1319 // All scalars or structs. Code after this test assumes this case is removed!
1320 //
1321 if (nominalSize == 1)
1322 {
1323 switch (mOp)
1324 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001325 //
1326 // Promote to conditional
1327 //
1328 case EOpEqual:
1329 case EOpNotEqual:
1330 case EOpLessThan:
1331 case EOpGreaterThan:
1332 case EOpLessThanEqual:
1333 case EOpGreaterThanEqual:
1334 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1335 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001336
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001337 //
1338 // And and Or operate on conditionals
1339 //
1340 case EOpLogicalAnd:
1341 case EOpLogicalXor:
1342 case EOpLogicalOr:
1343 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1344 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1345 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001346
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001347 default:
1348 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001349 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001350 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001351 }
1352
1353 // If we reach here, at least one of the operands is vector or matrix.
1354 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001355 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001356
Jamie Madillb1a85f42014-08-19 15:23:24 -04001357 switch (mOp)
1358 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001359 case EOpMul:
1360 break;
1361 case EOpMatrixTimesScalar:
1362 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001363 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001364 setType(TType(basicType, higherPrecision, resultQualifier,
1365 static_cast<unsigned char>(mRight->getCols()),
1366 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001367 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001368 break;
1369 case EOpMatrixTimesVector:
1370 setType(TType(basicType, higherPrecision, resultQualifier,
1371 static_cast<unsigned char>(mLeft->getRows()), 1));
1372 break;
1373 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001374 setType(TType(basicType, higherPrecision, resultQualifier,
1375 static_cast<unsigned char>(mRight->getCols()),
1376 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001377 break;
1378 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001379 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001380 static_cast<unsigned char>(nominalSize), 1));
1381 break;
1382 case EOpVectorTimesMatrix:
1383 setType(TType(basicType, higherPrecision, resultQualifier,
1384 static_cast<unsigned char>(mRight->getCols()), 1));
1385 break;
1386 case EOpMulAssign:
1387 case EOpVectorTimesScalarAssign:
1388 case EOpVectorTimesMatrixAssign:
1389 case EOpMatrixTimesScalarAssign:
1390 case EOpMatrixTimesMatrixAssign:
1391 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1392 break;
1393 case EOpAssign:
1394 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001395 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1396 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1397 break;
1398 case EOpAdd:
1399 case EOpSub:
1400 case EOpDiv:
1401 case EOpIMod:
1402 case EOpBitShiftLeft:
1403 case EOpBitShiftRight:
1404 case EOpBitwiseAnd:
1405 case EOpBitwiseXor:
1406 case EOpBitwiseOr:
1407 case EOpAddAssign:
1408 case EOpSubAssign:
1409 case EOpDivAssign:
1410 case EOpIModAssign:
1411 case EOpBitShiftLeftAssign:
1412 case EOpBitShiftRightAssign:
1413 case EOpBitwiseAndAssign:
1414 case EOpBitwiseXorAssign:
1415 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001416 {
1417 const int secondarySize =
1418 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1419 setType(TType(basicType, higherPrecision, resultQualifier,
1420 static_cast<unsigned char>(nominalSize),
1421 static_cast<unsigned char>(secondarySize)));
1422 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001423 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001424 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001425 case EOpEqual:
1426 case EOpNotEqual:
1427 case EOpLessThan:
1428 case EOpGreaterThan:
1429 case EOpLessThanEqual:
1430 case EOpGreaterThanEqual:
1431 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1432 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001433 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001434 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001435
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001436 case EOpIndexDirect:
1437 case EOpIndexIndirect:
1438 case EOpIndexDirectInterfaceBlock:
1439 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001440 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001441 UNREACHABLE();
1442 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001443 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001444 UNREACHABLE();
1445 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001446 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001447}
1448
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001449bool TIntermConstantUnion::hasConstantValue() const
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001450{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001451 return true;
1452}
1453
1454const TConstantUnion *TIntermConstantUnion::getConstantValue() const
1455{
1456 return mUnionArrayPointer;
1457}
1458
1459const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
1460 const TConstantUnion *constArray,
1461 int index)
1462{
1463 if (type.isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001464 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001465 ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
1466 TType arrayElementType(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001467 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001468 size_t arrayElementSize = arrayElementType.getObjectSize();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001469 return &constArray[arrayElementSize * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001470 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001471 else if (type.isMatrix())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001472 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001473 ASSERT(index < type.getCols());
1474 int size = type.getRows();
1475 return &constArray[size * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001476 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001477 else if (type.isVector())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001478 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001479 ASSERT(index < type.getNominalSize());
1480 return &constArray[index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001481 }
1482 else
1483 {
1484 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001485 return nullptr;
1486 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001487}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001488
Olli Etuaho765924f2018-01-04 12:48:36 +02001489TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001490{
1491 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1492 if (operandConstant == nullptr)
1493 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001494 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001495 }
1496
1497 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1498 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1499 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001500 constArray[i] = *TIntermConstantUnion::FoldIndexing(
1501 operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
Olli Etuahob6fa0432016-09-28 16:28:05 +01001502 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001503 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001504}
1505
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001506TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1507{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001508 const TConstantUnion *rightConstant = mRight->getConstantValue();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001509 switch (mOp)
1510 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001511 case EOpComma:
1512 {
1513 if (mLeft->hasSideEffects())
1514 {
1515 return this;
1516 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001517 return mRight;
1518 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001519 case EOpIndexDirect:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001520 case EOpIndexDirectStruct:
1521 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001522 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001523 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001524 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001525 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001526 size_t index = static_cast<size_t>(rightConstant->getIConst());
1527 TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
1528 if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
1529 !leftAggregate->hasSideEffects())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001530 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001531 ASSERT(index < leftAggregate->getSequence()->size());
1532 // This transformation can't add complexity as we're eliminating the constructor
1533 // entirely.
1534 return leftAggregate->getSequence()->at(index)->getAsTyped();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001535 }
1536
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001537 // If the indexed value is already a constant union, we can't increase duplication of
1538 // data by folding the indexing. Also fold the node in case it's generally beneficial to
1539 // replace this type of node with a constant union even if that would mean duplicating
1540 // data.
1541 if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
1542 {
1543 const TConstantUnion *constantValue = getConstantValue();
1544 if (constantValue == nullptr)
1545 {
1546 return this;
1547 }
1548 return CreateFoldedNode(constantValue, this);
1549 }
1550 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001551 }
1552 case EOpIndexIndirect:
1553 case EOpIndexDirectInterfaceBlock:
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001554 case EOpInitialize:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001555 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001556 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001557 default:
1558 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001559 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001560 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001561 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001562 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001563 const TConstantUnion *leftConstant = mLeft->getConstantValue();
1564 if (leftConstant == nullptr)
1565 {
1566 return this;
1567 }
1568 const TConstantUnion *constArray =
1569 TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
1570 mRight->getType(), diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001571 if (!constArray)
1572 {
1573 return this;
1574 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001575 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001576 }
1577 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001578}
1579
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001580bool TIntermBinary::hasConstantValue() const
1581{
1582 switch (mOp)
1583 {
1584 case EOpIndexDirect:
1585 case EOpIndexDirectStruct:
1586 {
1587 if (mLeft->hasConstantValue() && mRight->hasConstantValue())
1588 {
1589 return true;
1590 }
Nico Weber41b072b2018-02-09 10:01:32 -05001591 break;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001592 }
1593 default:
1594 break;
1595 }
1596 return false;
1597}
1598
1599const TConstantUnion *TIntermBinary::getConstantValue() const
1600{
1601 if (!hasConstantValue())
1602 {
1603 return nullptr;
1604 }
1605
1606 const TConstantUnion *leftConstantValue = mLeft->getConstantValue();
1607 int index = mRight->getConstantValue()->getIConst();
1608 const TConstantUnion *constIndexingResult = nullptr;
1609 if (mOp == EOpIndexDirect)
1610 {
1611 constIndexingResult =
1612 TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
1613 }
1614 else
1615 {
1616 ASSERT(mOp == EOpIndexDirectStruct);
1617 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1618
1619 size_t previousFieldsSize = 0;
1620 for (int i = 0; i < index; ++i)
1621 {
1622 previousFieldsSize += fields[i]->type()->getObjectSize();
1623 }
1624 constIndexingResult = leftConstantValue + previousFieldsSize;
1625 }
1626 return constIndexingResult;
1627}
1628
Olli Etuahof119a262016-08-19 15:54:22 +03001629TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001630{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301631 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001632
1633 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301634 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001635 // The size of runtime-sized arrays may only be determined at runtime.
1636 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001637 {
1638 return this;
1639 }
1640 constArray = new TConstantUnion[1];
1641 constArray->setIConst(mOperand->getOutermostArraySize());
1642 }
1643 else
1644 {
1645 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1646 if (operandConstant == nullptr)
1647 {
1648 return this;
1649 }
1650
1651 switch (mOp)
1652 {
1653 case EOpAny:
1654 case EOpAll:
1655 case EOpLength:
1656 case EOpTranspose:
1657 case EOpDeterminant:
1658 case EOpInverse:
1659 case EOpPackSnorm2x16:
1660 case EOpUnpackSnorm2x16:
1661 case EOpPackUnorm2x16:
1662 case EOpUnpackUnorm2x16:
1663 case EOpPackHalf2x16:
1664 case EOpUnpackHalf2x16:
1665 case EOpPackUnorm4x8:
1666 case EOpPackSnorm4x8:
1667 case EOpUnpackUnorm4x8:
1668 case EOpUnpackSnorm4x8:
1669 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1670 break;
1671 default:
1672 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1673 break;
1674 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301675 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001676 if (constArray == nullptr)
1677 {
1678 return this;
1679 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001680 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001681}
1682
Olli Etuahof119a262016-08-19 15:54:22 +03001683TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001684{
1685 // Make sure that all params are constant before actual constant folding.
1686 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001687 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001688 if (param->getAsConstantUnion() == nullptr)
1689 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001690 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001691 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001692 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001693 const TConstantUnion *constArray = nullptr;
Olli Etuaho1d122782015-11-06 15:35:17 +02001694 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001695 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001696 if (mType.canReplaceWithConstantUnion())
Olli Etuaho765924f2018-01-04 12:48:36 +02001697 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001698 constArray = getConstantValue();
Olli Etuaho765924f2018-01-04 12:48:36 +02001699 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001700 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001701 else if (CanFoldAggregateBuiltInOp(mOp))
Olli Etuaho2768bc82017-12-12 11:51:48 +02001702 {
Olli Etuahof119a262016-08-19 15:54:22 +03001703 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001704 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001705 if (constArray == nullptr)
1706 {
1707 return this;
1708 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001709 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001710}
1711
Jamie Madillb1a85f42014-08-19 15:23:24 -04001712//
1713// The fold functions see if an operation on a constant can be done in place,
1714// without generating run-time code.
1715//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001716// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001717//
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001718const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
1719 const TConstantUnion *leftArray,
1720 const TType &leftType,
1721 const TConstantUnion *rightArray,
1722 const TType &rightType,
1723 TDiagnostics *diagnostics,
1724 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001725{
Olli Etuahof119a262016-08-19 15:54:22 +03001726 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001727
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001728 size_t objectSize = leftType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001729
1730 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001731 if (rightType.getObjectSize() == 1 && objectSize > 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001732 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001733 rightArray = Vectorize(*rightArray, objectSize);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001734 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001735 else if (rightType.getObjectSize() > 1 && objectSize == 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001736 {
1737 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001738 leftArray = Vectorize(*leftArray, rightType.getObjectSize());
1739 objectSize = rightType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001740 }
1741
1742 TConstantUnion *resultArray = nullptr;
1743
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001744 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001745 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001746 case EOpAdd:
1747 resultArray = new TConstantUnion[objectSize];
1748 for (size_t i = 0; i < objectSize; i++)
1749 resultArray[i] =
1750 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1751 break;
1752 case EOpSub:
1753 resultArray = new TConstantUnion[objectSize];
1754 for (size_t i = 0; i < objectSize; i++)
1755 resultArray[i] =
1756 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1757 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001758
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001759 case EOpMul:
1760 case EOpVectorTimesScalar:
1761 case EOpMatrixTimesScalar:
1762 resultArray = new TConstantUnion[objectSize];
1763 for (size_t i = 0; i < objectSize; i++)
1764 resultArray[i] =
1765 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1766 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001767
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001768 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001769 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001770 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001771 ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001772
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001773 const int leftCols = leftType.getCols();
1774 const int leftRows = leftType.getRows();
1775 const int rightCols = rightType.getCols();
1776 const int rightRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001777 const int resultCols = rightCols;
1778 const int resultRows = leftRows;
1779
1780 resultArray = new TConstantUnion[resultCols * resultRows];
1781 for (int row = 0; row < resultRows; row++)
1782 {
1783 for (int column = 0; column < resultCols; column++)
1784 {
1785 resultArray[resultRows * column + row].setFConst(0.0f);
1786 for (int i = 0; i < leftCols; i++)
1787 {
1788 resultArray[resultRows * column + row].setFConst(
1789 resultArray[resultRows * column + row].getFConst() +
1790 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001791 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001792 }
1793 }
1794 }
1795 }
1796 break;
1797
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001798 case EOpDiv:
1799 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001800 {
1801 resultArray = new TConstantUnion[objectSize];
1802 for (size_t i = 0; i < objectSize; i++)
1803 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001804 switch (leftType.getBasicType())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001805 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001806 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001807 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001808 ASSERT(op == EOpDiv);
1809 float dividend = leftArray[i].getFConst();
1810 float divisor = rightArray[i].getFConst();
1811 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001812 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001813 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001814 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001815 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001816 line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001817 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001818 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001819 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001820 }
1821 else
1822 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001823 diagnostics->warning(line, "Divide by zero during constant folding",
1824 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001825 bool negativeResult =
1826 std::signbit(dividend) != std::signbit(divisor);
1827 resultArray[i].setFConst(
1828 negativeResult ? -std::numeric_limits<float>::infinity()
1829 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001830 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001831 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001832 else if (gl::isInf(dividend) && gl::isInf(divisor))
1833 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001834 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001835 "Infinity divided by infinity during constant "
1836 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001837 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001838 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1839 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001840 else
1841 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001842 float result = dividend / divisor;
1843 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001844 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001845 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001846 line, "Constant folded division overflowed to infinity", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001847 }
1848 resultArray[i].setFConst(result);
1849 }
1850 break;
1851 }
1852 case EbtInt:
1853 if (rightArray[i] == 0)
1854 {
1855 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001856 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001857 resultArray[i].setIConst(INT_MAX);
1858 }
1859 else
1860 {
1861 int lhs = leftArray[i].getIConst();
1862 int divisor = rightArray[i].getIConst();
1863 if (op == EOpDiv)
1864 {
1865 // Check for the special case where the minimum representable number
1866 // is
1867 // divided by -1. If left alone this leads to integer overflow in
1868 // C++.
1869 // ESSL 3.00.6 section 4.1.3 Integers:
1870 // "However, for the case where the minimum representable value is
1871 // divided by -1, it is allowed to return either the minimum
1872 // representable value or the maximum representable value."
1873 if (lhs == -0x7fffffff - 1 && divisor == -1)
1874 {
1875 resultArray[i].setIConst(0x7fffffff);
1876 }
1877 else
1878 {
1879 resultArray[i].setIConst(lhs / divisor);
1880 }
Olli Etuahod4453572016-09-27 13:21:46 +01001881 }
1882 else
1883 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001884 ASSERT(op == EOpIMod);
1885 if (lhs < 0 || divisor < 0)
1886 {
1887 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1888 // when
1889 // either one of the operands is negative.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001890 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001891 "Negative modulus operator operand "
1892 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001893 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001894 resultArray[i].setIConst(0);
1895 }
1896 else
1897 {
1898 resultArray[i].setIConst(lhs % divisor);
1899 }
Olli Etuahod4453572016-09-27 13:21:46 +01001900 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001901 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001902 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001903
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001904 case EbtUInt:
1905 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001906 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001907 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001908 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001909 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001910 }
1911 else
1912 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001913 if (op == EOpDiv)
1914 {
1915 resultArray[i].setUConst(leftArray[i].getUConst() /
1916 rightArray[i].getUConst());
1917 }
1918 else
1919 {
1920 ASSERT(op == EOpIMod);
1921 resultArray[i].setUConst(leftArray[i].getUConst() %
1922 rightArray[i].getUConst());
1923 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001924 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001925 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001926
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001927 default:
1928 UNREACHABLE();
1929 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001930 }
1931 }
1932 }
1933 break;
1934
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001935 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001936 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001937 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001938 ASSERT(rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001939
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001940 const int matrixCols = leftType.getCols();
1941 const int matrixRows = leftType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001942
1943 resultArray = new TConstantUnion[matrixRows];
1944
1945 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1946 {
1947 resultArray[matrixRow].setFConst(0.0f);
1948 for (int col = 0; col < matrixCols; col++)
1949 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001950 resultArray[matrixRow].setFConst(
1951 resultArray[matrixRow].getFConst() +
1952 leftArray[col * matrixRows + matrixRow].getFConst() *
1953 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001954 }
1955 }
1956 }
1957 break;
1958
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001959 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001960 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001961 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001962 ASSERT(leftType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001963
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001964 const int matrixCols = rightType.getCols();
1965 const int matrixRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001966
1967 resultArray = new TConstantUnion[matrixCols];
1968
1969 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1970 {
1971 resultArray[matrixCol].setFConst(0.0f);
1972 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1973 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001974 resultArray[matrixCol].setFConst(
1975 resultArray[matrixCol].getFConst() +
1976 leftArray[matrixRow].getFConst() *
1977 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001978 }
1979 }
1980 }
1981 break;
1982
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001983 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001984 {
1985 resultArray = new TConstantUnion[objectSize];
1986 for (size_t i = 0; i < objectSize; i++)
1987 {
1988 resultArray[i] = leftArray[i] && rightArray[i];
1989 }
1990 }
1991 break;
1992
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001993 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001994 {
1995 resultArray = new TConstantUnion[objectSize];
1996 for (size_t i = 0; i < objectSize; i++)
1997 {
1998 resultArray[i] = leftArray[i] || rightArray[i];
1999 }
2000 }
2001 break;
2002
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002003 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002004 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002005 ASSERT(leftType.getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002006 resultArray = new TConstantUnion[objectSize];
2007 for (size_t i = 0; i < objectSize; i++)
2008 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03002009 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002010 }
2011 }
2012 break;
2013
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002014 case EOpBitwiseAnd:
2015 resultArray = new TConstantUnion[objectSize];
2016 for (size_t i = 0; i < objectSize; i++)
2017 resultArray[i] = leftArray[i] & rightArray[i];
2018 break;
2019 case EOpBitwiseXor:
2020 resultArray = new TConstantUnion[objectSize];
2021 for (size_t i = 0; i < objectSize; i++)
2022 resultArray[i] = leftArray[i] ^ rightArray[i];
2023 break;
2024 case EOpBitwiseOr:
2025 resultArray = new TConstantUnion[objectSize];
2026 for (size_t i = 0; i < objectSize; i++)
2027 resultArray[i] = leftArray[i] | rightArray[i];
2028 break;
2029 case EOpBitShiftLeft:
2030 resultArray = new TConstantUnion[objectSize];
2031 for (size_t i = 0; i < objectSize; i++)
2032 resultArray[i] =
2033 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
2034 break;
2035 case EOpBitShiftRight:
2036 resultArray = new TConstantUnion[objectSize];
2037 for (size_t i = 0; i < objectSize; i++)
2038 resultArray[i] =
2039 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
2040 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002041
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002042 case EOpLessThan:
2043 ASSERT(objectSize == 1);
2044 resultArray = new TConstantUnion[1];
2045 resultArray->setBConst(*leftArray < *rightArray);
2046 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002047
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002048 case EOpGreaterThan:
2049 ASSERT(objectSize == 1);
2050 resultArray = new TConstantUnion[1];
2051 resultArray->setBConst(*leftArray > *rightArray);
2052 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002053
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002054 case EOpLessThanEqual:
2055 ASSERT(objectSize == 1);
2056 resultArray = new TConstantUnion[1];
2057 resultArray->setBConst(!(*leftArray > *rightArray));
2058 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002059
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002060 case EOpGreaterThanEqual:
2061 ASSERT(objectSize == 1);
2062 resultArray = new TConstantUnion[1];
2063 resultArray->setBConst(!(*leftArray < *rightArray));
2064 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002065
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002066 case EOpEqual:
2067 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002068 {
2069 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002070 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002071 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002072 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002073 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002074 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002075 equal = false;
2076 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002077 }
2078 }
2079 if (op == EOpEqual)
2080 {
2081 resultArray->setBConst(equal);
2082 }
2083 else
2084 {
2085 resultArray->setBConst(!equal);
2086 }
2087 }
2088 break;
2089
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002090 default:
2091 UNREACHABLE();
2092 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002093 }
2094 return resultArray;
2095}
2096
Olli Etuahof119a262016-08-19 15:54:22 +03002097// The fold functions do operations on a constant at GLSL compile time, without generating run-time
2098// code. Returns the constant value to keep using. Nullptr should not be returned.
2099TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04002100{
Olli Etuahof119a262016-08-19 15:54:22 +03002101 // Do operations where the return type may have a different number of components compared to the
2102 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04002103
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002104 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002105 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302106
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002107 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302108 TConstantUnion *resultArray = nullptr;
2109 switch (op)
2110 {
Olli Etuahof119a262016-08-19 15:54:22 +03002111 case EOpAny:
2112 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302113 resultArray = new TConstantUnion();
2114 resultArray->setBConst(false);
2115 for (size_t i = 0; i < objectSize; i++)
2116 {
2117 if (operandArray[i].getBConst())
2118 {
2119 resultArray->setBConst(true);
2120 break;
2121 }
2122 }
2123 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302124
Olli Etuahof119a262016-08-19 15:54:22 +03002125 case EOpAll:
2126 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302127 resultArray = new TConstantUnion();
2128 resultArray->setBConst(true);
2129 for (size_t i = 0; i < objectSize; i++)
2130 {
2131 if (!operandArray[i].getBConst())
2132 {
2133 resultArray->setBConst(false);
2134 break;
2135 }
2136 }
2137 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302138
Olli Etuahof119a262016-08-19 15:54:22 +03002139 case EOpLength:
2140 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302141 resultArray = new TConstantUnion();
2142 resultArray->setFConst(VectorLength(operandArray, objectSize));
2143 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302144
Olli Etuahof119a262016-08-19 15:54:22 +03002145 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302146 {
Olli Etuahof119a262016-08-19 15:54:22 +03002147 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302148 resultArray = new TConstantUnion[objectSize];
2149 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002150 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302151 SetUnionArrayFromMatrix(result, resultArray);
2152 break;
2153 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302154
Olli Etuahof119a262016-08-19 15:54:22 +03002155 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302156 {
Olli Etuahof119a262016-08-19 15:54:22 +03002157 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302158 unsigned int size = getType().getNominalSize();
2159 ASSERT(size >= 2 && size <= 4);
2160 resultArray = new TConstantUnion();
2161 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
2162 break;
2163 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302164
Olli Etuahof119a262016-08-19 15:54:22 +03002165 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302166 {
Olli Etuahof119a262016-08-19 15:54:22 +03002167 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302168 unsigned int size = getType().getNominalSize();
2169 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03002170 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05302171 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
2172 SetUnionArrayFromMatrix(result, resultArray);
2173 break;
2174 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302175
Olli Etuahof119a262016-08-19 15:54:22 +03002176 case EOpPackSnorm2x16:
2177 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302178 ASSERT(getType().getNominalSize() == 2);
2179 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002180 resultArray->setUConst(
2181 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302182 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302183
Olli Etuahof119a262016-08-19 15:54:22 +03002184 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302185 {
Olli Etuahof119a262016-08-19 15:54:22 +03002186 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302187 resultArray = new TConstantUnion[2];
2188 float f1, f2;
2189 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2190 resultArray[0].setFConst(f1);
2191 resultArray[1].setFConst(f2);
2192 break;
2193 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302194
Olli Etuahof119a262016-08-19 15:54:22 +03002195 case EOpPackUnorm2x16:
2196 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302197 ASSERT(getType().getNominalSize() == 2);
2198 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002199 resultArray->setUConst(
2200 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302201 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302202
Olli Etuahof119a262016-08-19 15:54:22 +03002203 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302204 {
Olli Etuahof119a262016-08-19 15:54:22 +03002205 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302206 resultArray = new TConstantUnion[2];
2207 float f1, f2;
2208 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2209 resultArray[0].setFConst(f1);
2210 resultArray[1].setFConst(f2);
2211 break;
2212 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302213
Olli Etuahof119a262016-08-19 15:54:22 +03002214 case EOpPackHalf2x16:
2215 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302216 ASSERT(getType().getNominalSize() == 2);
2217 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002218 resultArray->setUConst(
2219 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302220 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302221
Olli Etuahof119a262016-08-19 15:54:22 +03002222 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302223 {
Olli Etuahof119a262016-08-19 15:54:22 +03002224 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302225 resultArray = new TConstantUnion[2];
2226 float f1, f2;
2227 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2228 resultArray[0].setFConst(f1);
2229 resultArray[1].setFConst(f2);
2230 break;
2231 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302232
Olli Etuaho25aef452017-01-29 16:15:44 -08002233 case EOpPackUnorm4x8:
2234 {
2235 ASSERT(getType().getBasicType() == EbtFloat);
2236 resultArray = new TConstantUnion();
2237 resultArray->setUConst(
2238 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2239 operandArray[2].getFConst(), operandArray[3].getFConst()));
2240 break;
2241 }
2242 case EOpPackSnorm4x8:
2243 {
2244 ASSERT(getType().getBasicType() == EbtFloat);
2245 resultArray = new TConstantUnion();
2246 resultArray->setUConst(
2247 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2248 operandArray[2].getFConst(), operandArray[3].getFConst()));
2249 break;
2250 }
2251 case EOpUnpackUnorm4x8:
2252 {
2253 ASSERT(getType().getBasicType() == EbtUInt);
2254 resultArray = new TConstantUnion[4];
2255 float f[4];
2256 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2257 for (size_t i = 0; i < 4; ++i)
2258 {
2259 resultArray[i].setFConst(f[i]);
2260 }
2261 break;
2262 }
2263 case EOpUnpackSnorm4x8:
2264 {
2265 ASSERT(getType().getBasicType() == EbtUInt);
2266 resultArray = new TConstantUnion[4];
2267 float f[4];
2268 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2269 for (size_t i = 0; i < 4; ++i)
2270 {
2271 resultArray[i].setFConst(f[i]);
2272 }
2273 break;
2274 }
2275
Olli Etuahof119a262016-08-19 15:54:22 +03002276 default:
2277 UNREACHABLE();
2278 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302279 }
2280
2281 return resultArray;
2282}
2283
Olli Etuahof119a262016-08-19 15:54:22 +03002284TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2285 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302286{
Olli Etuahof119a262016-08-19 15:54:22 +03002287 // Do unary operations where each component of the result is computed based on the corresponding
2288 // component of the operand. Also folds normalize, though the divisor in that case takes all
2289 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302290
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002291 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002292 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002293
2294 size_t objectSize = getType().getObjectSize();
2295
Arun Patoleab2b9a22015-07-06 18:27:56 +05302296 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2297 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302298 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002299 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302300 {
Olli Etuahof119a262016-08-19 15:54:22 +03002301 case EOpNegative:
2302 switch (getType().getBasicType())
2303 {
2304 case EbtFloat:
2305 resultArray[i].setFConst(-operandArray[i].getFConst());
2306 break;
2307 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002308 if (operandArray[i] == std::numeric_limits<int>::min())
2309 {
2310 // The minimum representable integer doesn't have a positive
2311 // counterpart, rather the negation overflows and in ESSL is supposed to
2312 // wrap back to the minimum representable integer. Make sure that we
2313 // don't actually let the negation overflow, which has undefined
2314 // behavior in C++.
2315 resultArray[i].setIConst(std::numeric_limits<int>::min());
2316 }
2317 else
2318 {
2319 resultArray[i].setIConst(-operandArray[i].getIConst());
2320 }
Olli Etuahof119a262016-08-19 15:54:22 +03002321 break;
2322 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002323 if (operandArray[i] == 0x80000000u)
2324 {
2325 resultArray[i].setUConst(0x80000000u);
2326 }
2327 else
2328 {
2329 resultArray[i].setUConst(static_cast<unsigned int>(
2330 -static_cast<int>(operandArray[i].getUConst())));
2331 }
Olli Etuahof119a262016-08-19 15:54:22 +03002332 break;
2333 default:
2334 UNREACHABLE();
2335 return nullptr;
2336 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302337 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302338
Olli Etuahof119a262016-08-19 15:54:22 +03002339 case EOpPositive:
2340 switch (getType().getBasicType())
2341 {
2342 case EbtFloat:
2343 resultArray[i].setFConst(operandArray[i].getFConst());
2344 break;
2345 case EbtInt:
2346 resultArray[i].setIConst(operandArray[i].getIConst());
2347 break;
2348 case EbtUInt:
2349 resultArray[i].setUConst(static_cast<unsigned int>(
2350 static_cast<int>(operandArray[i].getUConst())));
2351 break;
2352 default:
2353 UNREACHABLE();
2354 return nullptr;
2355 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302356 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302357
Olli Etuahof119a262016-08-19 15:54:22 +03002358 case EOpLogicalNot:
2359 switch (getType().getBasicType())
2360 {
2361 case EbtBool:
2362 resultArray[i].setBConst(!operandArray[i].getBConst());
2363 break;
2364 default:
2365 UNREACHABLE();
2366 return nullptr;
2367 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302368 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302369
Olli Etuahof119a262016-08-19 15:54:22 +03002370 case EOpBitwiseNot:
2371 switch (getType().getBasicType())
2372 {
2373 case EbtInt:
2374 resultArray[i].setIConst(~operandArray[i].getIConst());
2375 break;
2376 case EbtUInt:
2377 resultArray[i].setUConst(~operandArray[i].getUConst());
2378 break;
2379 default:
2380 UNREACHABLE();
2381 return nullptr;
2382 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302383 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302384
Olli Etuahof119a262016-08-19 15:54:22 +03002385 case EOpRadians:
2386 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302387 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2388 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302389
Olli Etuahof119a262016-08-19 15:54:22 +03002390 case EOpDegrees:
2391 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302392 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2393 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302394
Olli Etuahof119a262016-08-19 15:54:22 +03002395 case EOpSin:
2396 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302397 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302398
Olli Etuahof119a262016-08-19 15:54:22 +03002399 case EOpCos:
2400 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2401 break;
2402
2403 case EOpTan:
2404 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2405 break;
2406
2407 case EOpAsin:
2408 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2409 // 0.
2410 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2411 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2412 diagnostics, &resultArray[i]);
2413 else
2414 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2415 break;
2416
2417 case EOpAcos:
2418 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2419 // 0.
2420 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2421 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2422 diagnostics, &resultArray[i]);
2423 else
2424 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2425 break;
2426
2427 case EOpAtan:
2428 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2429 break;
2430
2431 case EOpSinh:
2432 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2433 break;
2434
2435 case EOpCosh:
2436 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2437 break;
2438
2439 case EOpTanh:
2440 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2441 break;
2442
2443 case EOpAsinh:
2444 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2445 break;
2446
2447 case EOpAcosh:
2448 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2449 if (operandArray[i].getFConst() < 1.0f)
2450 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2451 diagnostics, &resultArray[i]);
2452 else
2453 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2454 break;
2455
2456 case EOpAtanh:
2457 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2458 // 0.
2459 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2460 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2461 diagnostics, &resultArray[i]);
2462 else
2463 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2464 break;
2465
2466 case EOpAbs:
2467 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302468 {
Olli Etuahof119a262016-08-19 15:54:22 +03002469 case EbtFloat:
2470 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2471 break;
2472 case EbtInt:
2473 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2474 break;
2475 default:
2476 UNREACHABLE();
2477 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302478 }
2479 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002480
2481 case EOpSign:
2482 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302483 {
Olli Etuahof119a262016-08-19 15:54:22 +03002484 case EbtFloat:
2485 {
2486 float fConst = operandArray[i].getFConst();
2487 float fResult = 0.0f;
2488 if (fConst > 0.0f)
2489 fResult = 1.0f;
2490 else if (fConst < 0.0f)
2491 fResult = -1.0f;
2492 resultArray[i].setFConst(fResult);
2493 break;
2494 }
2495 case EbtInt:
2496 {
2497 int iConst = operandArray[i].getIConst();
2498 int iResult = 0;
2499 if (iConst > 0)
2500 iResult = 1;
2501 else if (iConst < 0)
2502 iResult = -1;
2503 resultArray[i].setIConst(iResult);
2504 break;
2505 }
2506 default:
2507 UNREACHABLE();
2508 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302509 }
2510 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302511
Olli Etuahof119a262016-08-19 15:54:22 +03002512 case EOpFloor:
2513 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2514 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302515
Olli Etuahof119a262016-08-19 15:54:22 +03002516 case EOpTrunc:
2517 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2518 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302519
Olli Etuahof119a262016-08-19 15:54:22 +03002520 case EOpRound:
2521 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2522 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302523
Olli Etuahof119a262016-08-19 15:54:22 +03002524 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302525 {
Olli Etuahof119a262016-08-19 15:54:22 +03002526 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302527 float x = operandArray[i].getFConst();
2528 float result;
2529 float fractPart = modff(x, &result);
2530 if (fabsf(fractPart) == 0.5f)
2531 result = 2.0f * roundf(x / 2.0f);
2532 else
2533 result = roundf(x);
2534 resultArray[i].setFConst(result);
2535 break;
2536 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302537
Olli Etuahof119a262016-08-19 15:54:22 +03002538 case EOpCeil:
2539 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2540 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302541
Olli Etuahof119a262016-08-19 15:54:22 +03002542 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302543 {
Olli Etuahof119a262016-08-19 15:54:22 +03002544 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302545 float x = operandArray[i].getFConst();
2546 resultArray[i].setFConst(x - floorf(x));
2547 break;
2548 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302549
Olli Etuahof119a262016-08-19 15:54:22 +03002550 case EOpIsNan:
2551 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302552 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2553 break;
Arun Patole551279e2015-07-07 18:18:23 +05302554
Olli Etuahof119a262016-08-19 15:54:22 +03002555 case EOpIsInf:
2556 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302557 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2558 break;
Arun Patole551279e2015-07-07 18:18:23 +05302559
Olli Etuahof119a262016-08-19 15:54:22 +03002560 case EOpFloatBitsToInt:
2561 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302562 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2563 break;
Arun Patole551279e2015-07-07 18:18:23 +05302564
Olli Etuahof119a262016-08-19 15:54:22 +03002565 case EOpFloatBitsToUint:
2566 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302567 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2568 break;
Arun Patole551279e2015-07-07 18:18:23 +05302569
Olli Etuahof119a262016-08-19 15:54:22 +03002570 case EOpIntBitsToFloat:
2571 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302572 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2573 break;
Arun Patole551279e2015-07-07 18:18:23 +05302574
Olli Etuahof119a262016-08-19 15:54:22 +03002575 case EOpUintBitsToFloat:
2576 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302577 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2578 break;
Arun Patole551279e2015-07-07 18:18:23 +05302579
Olli Etuahof119a262016-08-19 15:54:22 +03002580 case EOpExp:
2581 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2582 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302583
Olli Etuahof119a262016-08-19 15:54:22 +03002584 case EOpLog:
2585 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2586 if (operandArray[i].getFConst() <= 0.0f)
2587 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2588 diagnostics, &resultArray[i]);
2589 else
2590 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2591 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302592
Olli Etuahof119a262016-08-19 15:54:22 +03002593 case EOpExp2:
2594 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2595 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302596
Olli Etuahof119a262016-08-19 15:54:22 +03002597 case EOpLog2:
2598 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2599 // And log2f is not available on some plarforms like old android, so just using
2600 // log(x)/log(2) here.
2601 if (operandArray[i].getFConst() <= 0.0f)
2602 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2603 diagnostics, &resultArray[i]);
2604 else
2605 {
2606 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2607 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2608 }
2609 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302610
Olli Etuahof119a262016-08-19 15:54:22 +03002611 case EOpSqrt:
2612 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2613 if (operandArray[i].getFConst() < 0.0f)
2614 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2615 diagnostics, &resultArray[i]);
2616 else
2617 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2618 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302619
Olli Etuahof119a262016-08-19 15:54:22 +03002620 case EOpInverseSqrt:
2621 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2622 // so getting the square root first using builtin function sqrt() and then taking
2623 // its inverse.
2624 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2625 // result to 0.
2626 if (operandArray[i].getFConst() <= 0.0f)
2627 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2628 diagnostics, &resultArray[i]);
2629 else
2630 {
2631 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2632 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2633 }
2634 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302635
Olli Etuahod68924e2017-01-02 17:34:40 +00002636 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002637 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302638 resultArray[i].setBConst(!operandArray[i].getBConst());
2639 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302640
Olli Etuahof119a262016-08-19 15:54:22 +03002641 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302642 {
Olli Etuahof119a262016-08-19 15:54:22 +03002643 ASSERT(getType().getBasicType() == EbtFloat);
2644 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302645 float length = VectorLength(operandArray, objectSize);
2646 if (length)
2647 resultArray[i].setFConst(x / length);
2648 else
Olli Etuahof119a262016-08-19 15:54:22 +03002649 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2650 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302651 break;
2652 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002653 case EOpBitfieldReverse:
2654 {
2655 uint32_t value;
2656 if (getType().getBasicType() == EbtInt)
2657 {
2658 value = static_cast<uint32_t>(operandArray[i].getIConst());
2659 }
2660 else
2661 {
2662 ASSERT(getType().getBasicType() == EbtUInt);
2663 value = operandArray[i].getUConst();
2664 }
2665 uint32_t result = gl::BitfieldReverse(value);
2666 if (getType().getBasicType() == EbtInt)
2667 {
2668 resultArray[i].setIConst(static_cast<int32_t>(result));
2669 }
2670 else
2671 {
2672 resultArray[i].setUConst(result);
2673 }
2674 break;
2675 }
2676 case EOpBitCount:
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 int result = gl::BitCount(value);
2689 resultArray[i].setIConst(result);
2690 break;
2691 }
2692 case EOpFindLSB:
2693 {
2694 uint32_t value;
2695 if (getType().getBasicType() == EbtInt)
2696 {
2697 value = static_cast<uint32_t>(operandArray[i].getIConst());
2698 }
2699 else
2700 {
2701 ASSERT(getType().getBasicType() == EbtUInt);
2702 value = operandArray[i].getUConst();
2703 }
2704 resultArray[i].setIConst(gl::FindLSB(value));
2705 break;
2706 }
2707 case EOpFindMSB:
2708 {
2709 uint32_t value;
2710 if (getType().getBasicType() == EbtInt)
2711 {
2712 int intValue = operandArray[i].getIConst();
2713 value = static_cast<uint32_t>(intValue);
2714 if (intValue < 0)
2715 {
2716 // Look for zero instead of one in value. This also handles the intValue ==
2717 // -1 special case, where the return value needs to be -1.
2718 value = ~value;
2719 }
2720 }
2721 else
2722 {
2723 ASSERT(getType().getBasicType() == EbtUInt);
2724 value = operandArray[i].getUConst();
2725 }
2726 resultArray[i].setIConst(gl::FindMSB(value));
2727 break;
2728 }
Olli Etuahof119a262016-08-19 15:54:22 +03002729 case EOpDFdx:
2730 case EOpDFdy:
2731 case EOpFwidth:
2732 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302733 // Derivatives of constant arguments should be 0.
2734 resultArray[i].setFConst(0.0f);
2735 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302736
Olli Etuahof119a262016-08-19 15:54:22 +03002737 default:
2738 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302739 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302740 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002741
Arun Patoleab2b9a22015-07-06 18:27:56 +05302742 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002743}
2744
Olli Etuahof119a262016-08-19 15:54:22 +03002745void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2746 FloatTypeUnaryFunc builtinFunc,
2747 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302748{
2749 ASSERT(builtinFunc);
2750
Olli Etuahof119a262016-08-19 15:54:22 +03002751 ASSERT(getType().getBasicType() == EbtFloat);
2752 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302753}
2754
Jamie Madillb1a85f42014-08-19 15:23:24 -04002755// static
Olli Etuahof119a262016-08-19 15:54:22 +03002756TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2757 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302758{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002759 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002760 TIntermSequence *arguments = aggregate->getSequence();
2761 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2762 std::vector<const TConstantUnion *> unionArrays(argsCount);
2763 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002764 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302765 TBasicType basicType = EbtVoid;
2766 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002767 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302768 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002769 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2770 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302771
2772 if (i == 0)
2773 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002774 basicType = argConstant->getType().getBasicType();
2775 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302776 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002777 unionArrays[i] = argConstant->getConstantValue();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002778 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002779 if (objectSizes[i] > maxObjectSize)
2780 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302781 }
2782
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002783 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302784 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002785 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302786 if (objectSizes[i] != maxObjectSize)
2787 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2788 }
Arun Patole274f0702015-05-05 13:33:30 +05302789
Olli Etuahob43846e2015-06-02 18:18:57 +03002790 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002791
2792 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302793 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002794 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302795 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002796 ASSERT(basicType == EbtFloat);
2797 resultArray = new TConstantUnion[maxObjectSize];
2798 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302799 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002800 float y = unionArrays[0][i].getFConst();
2801 float x = unionArrays[1][i].getFConst();
2802 // Results are undefined if x and y are both 0.
2803 if (x == 0.0f && y == 0.0f)
2804 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2805 else
2806 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302807 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002808 break;
2809 }
Arun Patolebf790422015-05-18 17:53:04 +05302810
Olli Etuaho51182ab2017-01-22 00:12:29 +00002811 case EOpPow:
2812 {
2813 ASSERT(basicType == EbtFloat);
2814 resultArray = new TConstantUnion[maxObjectSize];
2815 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302816 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002817 float x = unionArrays[0][i].getFConst();
2818 float y = unionArrays[1][i].getFConst();
2819 // Results are undefined if x < 0.
2820 // Results are undefined if x = 0 and y <= 0.
2821 if (x < 0.0f)
2822 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2823 else if (x == 0.0f && y <= 0.0f)
2824 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2825 else
2826 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302827 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002828 break;
2829 }
Arun Patolebf790422015-05-18 17:53:04 +05302830
Olli Etuaho51182ab2017-01-22 00:12:29 +00002831 case EOpMod:
2832 {
2833 ASSERT(basicType == EbtFloat);
2834 resultArray = new TConstantUnion[maxObjectSize];
2835 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302836 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002837 float x = unionArrays[0][i].getFConst();
2838 float y = unionArrays[1][i].getFConst();
2839 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302840 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002841 break;
2842 }
Arun Patolebf790422015-05-18 17:53:04 +05302843
Olli Etuaho51182ab2017-01-22 00:12:29 +00002844 case EOpMin:
2845 {
2846 resultArray = new TConstantUnion[maxObjectSize];
2847 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302848 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002849 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302850 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002851 case EbtFloat:
2852 resultArray[i].setFConst(
2853 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2854 break;
2855 case EbtInt:
2856 resultArray[i].setIConst(
2857 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2858 break;
2859 case EbtUInt:
2860 resultArray[i].setUConst(
2861 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2862 break;
2863 default:
2864 UNREACHABLE();
2865 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302866 }
2867 }
2868 break;
Arun Patole274f0702015-05-05 13:33:30 +05302869 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002870
2871 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302872 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002873 resultArray = new TConstantUnion[maxObjectSize];
2874 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302875 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002876 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302877 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002878 case EbtFloat:
2879 resultArray[i].setFConst(
2880 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2881 break;
2882 case EbtInt:
2883 resultArray[i].setIConst(
2884 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2885 break;
2886 case EbtUInt:
2887 resultArray[i].setUConst(
2888 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2889 break;
2890 default:
2891 UNREACHABLE();
2892 break;
Arun Patole274f0702015-05-05 13:33:30 +05302893 }
2894 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002895 break;
Arun Patole274f0702015-05-05 13:33:30 +05302896 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002897
2898 case EOpStep:
2899 {
2900 ASSERT(basicType == EbtFloat);
2901 resultArray = new TConstantUnion[maxObjectSize];
2902 for (size_t i = 0; i < maxObjectSize; i++)
2903 resultArray[i].setFConst(
2904 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2905 break;
2906 }
2907
2908 case EOpLessThanComponentWise:
2909 {
2910 resultArray = new TConstantUnion[maxObjectSize];
2911 for (size_t i = 0; i < maxObjectSize; i++)
2912 {
2913 switch (basicType)
2914 {
2915 case EbtFloat:
2916 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2917 unionArrays[1][i].getFConst());
2918 break;
2919 case EbtInt:
2920 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2921 unionArrays[1][i].getIConst());
2922 break;
2923 case EbtUInt:
2924 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2925 unionArrays[1][i].getUConst());
2926 break;
2927 default:
2928 UNREACHABLE();
2929 break;
2930 }
2931 }
2932 break;
2933 }
2934
2935 case EOpLessThanEqualComponentWise:
2936 {
2937 resultArray = new TConstantUnion[maxObjectSize];
2938 for (size_t i = 0; i < maxObjectSize; i++)
2939 {
2940 switch (basicType)
2941 {
2942 case EbtFloat:
2943 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2944 unionArrays[1][i].getFConst());
2945 break;
2946 case EbtInt:
2947 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2948 unionArrays[1][i].getIConst());
2949 break;
2950 case EbtUInt:
2951 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2952 unionArrays[1][i].getUConst());
2953 break;
2954 default:
2955 UNREACHABLE();
2956 break;
2957 }
2958 }
2959 break;
2960 }
2961
2962 case EOpGreaterThanComponentWise:
2963 {
2964 resultArray = new TConstantUnion[maxObjectSize];
2965 for (size_t i = 0; i < maxObjectSize; i++)
2966 {
2967 switch (basicType)
2968 {
2969 case EbtFloat:
2970 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2971 unionArrays[1][i].getFConst());
2972 break;
2973 case EbtInt:
2974 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2975 unionArrays[1][i].getIConst());
2976 break;
2977 case EbtUInt:
2978 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2979 unionArrays[1][i].getUConst());
2980 break;
2981 default:
2982 UNREACHABLE();
2983 break;
2984 }
2985 }
2986 break;
2987 }
2988 case EOpGreaterThanEqualComponentWise:
2989 {
2990 resultArray = new TConstantUnion[maxObjectSize];
2991 for (size_t i = 0; i < maxObjectSize; i++)
2992 {
2993 switch (basicType)
2994 {
2995 case EbtFloat:
2996 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2997 unionArrays[1][i].getFConst());
2998 break;
2999 case EbtInt:
3000 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
3001 unionArrays[1][i].getIConst());
3002 break;
3003 case EbtUInt:
3004 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
3005 unionArrays[1][i].getUConst());
3006 break;
3007 default:
3008 UNREACHABLE();
3009 break;
3010 }
3011 }
3012 }
3013 break;
3014
3015 case EOpEqualComponentWise:
3016 {
3017 resultArray = new TConstantUnion[maxObjectSize];
3018 for (size_t i = 0; i < maxObjectSize; i++)
3019 {
3020 switch (basicType)
3021 {
3022 case EbtFloat:
3023 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
3024 unionArrays[1][i].getFConst());
3025 break;
3026 case EbtInt:
3027 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
3028 unionArrays[1][i].getIConst());
3029 break;
3030 case EbtUInt:
3031 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
3032 unionArrays[1][i].getUConst());
3033 break;
3034 case EbtBool:
3035 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
3036 unionArrays[1][i].getBConst());
3037 break;
3038 default:
3039 UNREACHABLE();
3040 break;
3041 }
3042 }
3043 break;
3044 }
3045
3046 case EOpNotEqualComponentWise:
3047 {
3048 resultArray = new TConstantUnion[maxObjectSize];
3049 for (size_t i = 0; i < maxObjectSize; i++)
3050 {
3051 switch (basicType)
3052 {
3053 case EbtFloat:
3054 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
3055 unionArrays[1][i].getFConst());
3056 break;
3057 case EbtInt:
3058 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3059 unionArrays[1][i].getIConst());
3060 break;
3061 case EbtUInt:
3062 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3063 unionArrays[1][i].getUConst());
3064 break;
3065 case EbtBool:
3066 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3067 unionArrays[1][i].getBConst());
3068 break;
3069 default:
3070 UNREACHABLE();
3071 break;
3072 }
3073 }
3074 break;
3075 }
3076
3077 case EOpDistance:
3078 {
3079 ASSERT(basicType == EbtFloat);
3080 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3081 resultArray = new TConstantUnion();
3082 for (size_t i = 0; i < maxObjectSize; i++)
3083 {
3084 float x = unionArrays[0][i].getFConst();
3085 float y = unionArrays[1][i].getFConst();
3086 distanceArray[i].setFConst(x - y);
3087 }
3088 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3089 break;
3090 }
3091
3092 case EOpDot:
3093 ASSERT(basicType == EbtFloat);
3094 resultArray = new TConstantUnion();
3095 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3096 break;
3097
3098 case EOpCross:
3099 {
3100 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3101 resultArray = new TConstantUnion[maxObjectSize];
3102 float x0 = unionArrays[0][0].getFConst();
3103 float x1 = unionArrays[0][1].getFConst();
3104 float x2 = unionArrays[0][2].getFConst();
3105 float y0 = unionArrays[1][0].getFConst();
3106 float y1 = unionArrays[1][1].getFConst();
3107 float y2 = unionArrays[1][2].getFConst();
3108 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3109 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3110 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3111 break;
3112 }
3113
3114 case EOpReflect:
3115 {
3116 ASSERT(basicType == EbtFloat);
3117 // genType reflect (genType I, genType N) :
3118 // For the incident vector I and surface orientation N, returns the reflection
3119 // direction:
3120 // I - 2 * dot(N, I) * N.
3121 resultArray = new TConstantUnion[maxObjectSize];
3122 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3123 for (size_t i = 0; i < maxObjectSize; i++)
3124 {
3125 float result = unionArrays[0][i].getFConst() -
3126 2.0f * dotProduct * unionArrays[1][i].getFConst();
3127 resultArray[i].setFConst(result);
3128 }
3129 break;
3130 }
3131
3132 case EOpMulMatrixComponentWise:
3133 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003134 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3135 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003136 // Perform component-wise matrix multiplication.
3137 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003138 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003139 angle::Matrix<float> result =
3140 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3141 SetUnionArrayFromMatrix(result, resultArray);
3142 break;
3143 }
3144
3145 case EOpOuterProduct:
3146 {
3147 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003148 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3149 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003150 resultArray = new TConstantUnion[numRows * numCols];
3151 angle::Matrix<float> result =
3152 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3153 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3154 SetUnionArrayFromMatrix(result, resultArray);
3155 break;
3156 }
3157
3158 case EOpClamp:
3159 {
3160 resultArray = new TConstantUnion[maxObjectSize];
3161 for (size_t i = 0; i < maxObjectSize; i++)
3162 {
3163 switch (basicType)
3164 {
3165 case EbtFloat:
3166 {
3167 float x = unionArrays[0][i].getFConst();
3168 float min = unionArrays[1][i].getFConst();
3169 float max = unionArrays[2][i].getFConst();
3170 // Results are undefined if min > max.
3171 if (min > max)
3172 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3173 &resultArray[i]);
3174 else
3175 resultArray[i].setFConst(gl::clamp(x, min, max));
3176 break;
3177 }
3178
3179 case EbtInt:
3180 {
3181 int x = unionArrays[0][i].getIConst();
3182 int min = unionArrays[1][i].getIConst();
3183 int max = unionArrays[2][i].getIConst();
3184 // Results are undefined if min > max.
3185 if (min > max)
3186 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3187 &resultArray[i]);
3188 else
3189 resultArray[i].setIConst(gl::clamp(x, min, max));
3190 break;
3191 }
3192 case EbtUInt:
3193 {
3194 unsigned int x = unionArrays[0][i].getUConst();
3195 unsigned int min = unionArrays[1][i].getUConst();
3196 unsigned int max = unionArrays[2][i].getUConst();
3197 // Results are undefined if min > max.
3198 if (min > max)
3199 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3200 &resultArray[i]);
3201 else
3202 resultArray[i].setUConst(gl::clamp(x, min, max));
3203 break;
3204 }
3205 default:
3206 UNREACHABLE();
3207 break;
3208 }
3209 }
3210 break;
3211 }
3212
3213 case EOpMix:
3214 {
3215 ASSERT(basicType == EbtFloat);
3216 resultArray = new TConstantUnion[maxObjectSize];
3217 for (size_t i = 0; i < maxObjectSize; i++)
3218 {
3219 float x = unionArrays[0][i].getFConst();
3220 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003221 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003222 if (type == EbtFloat)
3223 {
3224 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3225 float a = unionArrays[2][i].getFConst();
3226 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3227 }
3228 else // 3rd parameter is EbtBool
3229 {
3230 ASSERT(type == EbtBool);
3231 // Selects which vector each returned component comes from.
3232 // For a component of a that is false, the corresponding component of x is
3233 // returned.
3234 // For a component of a that is true, the corresponding component of y is
3235 // returned.
3236 bool a = unionArrays[2][i].getBConst();
3237 resultArray[i].setFConst(a ? y : x);
3238 }
3239 }
3240 break;
3241 }
3242
3243 case EOpSmoothStep:
3244 {
3245 ASSERT(basicType == EbtFloat);
3246 resultArray = new TConstantUnion[maxObjectSize];
3247 for (size_t i = 0; i < maxObjectSize; i++)
3248 {
3249 float edge0 = unionArrays[0][i].getFConst();
3250 float edge1 = unionArrays[1][i].getFConst();
3251 float x = unionArrays[2][i].getFConst();
3252 // Results are undefined if edge0 >= edge1.
3253 if (edge0 >= edge1)
3254 {
3255 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3256 }
3257 else
3258 {
3259 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3260 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3261 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3262 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3263 }
3264 }
3265 break;
3266 }
3267
Olli Etuaho74da73f2017-02-01 15:37:48 +00003268 case EOpLdexp:
3269 {
3270 resultArray = new TConstantUnion[maxObjectSize];
3271 for (size_t i = 0; i < maxObjectSize; i++)
3272 {
3273 float x = unionArrays[0][i].getFConst();
3274 int exp = unionArrays[1][i].getIConst();
3275 if (exp > 128)
3276 {
3277 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3278 }
3279 else
3280 {
3281 resultArray[i].setFConst(gl::Ldexp(x, exp));
3282 }
3283 }
3284 break;
3285 }
3286
Jamie Madille72595b2017-06-06 15:12:26 -04003287 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003288 {
3289 ASSERT(basicType == EbtFloat);
3290 // genType faceforward(genType N, genType I, genType Nref) :
3291 // If dot(Nref, I) < 0 return N, otherwise return -N.
3292 resultArray = new TConstantUnion[maxObjectSize];
3293 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3294 for (size_t i = 0; i < maxObjectSize; i++)
3295 {
3296 if (dotProduct < 0)
3297 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3298 else
3299 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3300 }
3301 break;
3302 }
3303
3304 case EOpRefract:
3305 {
3306 ASSERT(basicType == EbtFloat);
3307 // genType refract(genType I, genType N, float eta) :
3308 // For the incident vector I and surface normal N, and the ratio of indices of
3309 // refraction eta,
3310 // return the refraction vector. The result is computed by
3311 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3312 // if (k < 0.0)
3313 // return genType(0.0)
3314 // else
3315 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3316 resultArray = new TConstantUnion[maxObjectSize];
3317 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3318 for (size_t i = 0; i < maxObjectSize; i++)
3319 {
3320 float eta = unionArrays[2][i].getFConst();
3321 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3322 if (k < 0.0f)
3323 resultArray[i].setFConst(0.0f);
3324 else
3325 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3326 (eta * dotProduct + sqrtf(k)) *
3327 unionArrays[1][i].getFConst());
3328 }
3329 break;
3330 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003331 case EOpBitfieldExtract:
3332 {
3333 resultArray = new TConstantUnion[maxObjectSize];
3334 for (size_t i = 0; i < maxObjectSize; ++i)
3335 {
3336 int offset = unionArrays[1][0].getIConst();
3337 int bits = unionArrays[2][0].getIConst();
3338 if (bits == 0)
3339 {
3340 if (aggregate->getBasicType() == EbtInt)
3341 {
3342 resultArray[i].setIConst(0);
3343 }
3344 else
3345 {
3346 ASSERT(aggregate->getBasicType() == EbtUInt);
3347 resultArray[i].setUConst(0);
3348 }
3349 }
3350 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3351 {
3352 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3353 &resultArray[i]);
3354 }
3355 else
3356 {
3357 // bits can be 32 here, so we need to avoid bit shift overflow.
3358 uint32_t maskMsb = 1u << (bits - 1);
3359 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3360 if (aggregate->getBasicType() == EbtInt)
3361 {
3362 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3363 uint32_t resultUnsigned = (value & mask) >> offset;
3364 if ((resultUnsigned & maskMsb) != 0)
3365 {
3366 // The most significant bits (from bits+1 to the most significant bit)
3367 // should be set to 1.
3368 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3369 resultUnsigned |= higherBitsMask;
3370 }
3371 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3372 }
3373 else
3374 {
3375 ASSERT(aggregate->getBasicType() == EbtUInt);
3376 uint32_t value = unionArrays[0][i].getUConst();
3377 resultArray[i].setUConst((value & mask) >> offset);
3378 }
3379 }
3380 }
3381 break;
3382 }
3383 case EOpBitfieldInsert:
3384 {
3385 resultArray = new TConstantUnion[maxObjectSize];
3386 for (size_t i = 0; i < maxObjectSize; ++i)
3387 {
3388 int offset = unionArrays[2][0].getIConst();
3389 int bits = unionArrays[3][0].getIConst();
3390 if (bits == 0)
3391 {
3392 if (aggregate->getBasicType() == EbtInt)
3393 {
3394 int32_t base = unionArrays[0][i].getIConst();
3395 resultArray[i].setIConst(base);
3396 }
3397 else
3398 {
3399 ASSERT(aggregate->getBasicType() == EbtUInt);
3400 uint32_t base = unionArrays[0][i].getUConst();
3401 resultArray[i].setUConst(base);
3402 }
3403 }
3404 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3405 {
3406 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3407 &resultArray[i]);
3408 }
3409 else
3410 {
3411 // bits can be 32 here, so we need to avoid bit shift overflow.
3412 uint32_t maskMsb = 1u << (bits - 1);
3413 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3414 uint32_t baseMask = ~insertMask;
3415 if (aggregate->getBasicType() == EbtInt)
3416 {
3417 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3418 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3419 uint32_t resultUnsigned =
3420 (base & baseMask) | ((insert << offset) & insertMask);
3421 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3422 }
3423 else
3424 {
3425 ASSERT(aggregate->getBasicType() == EbtUInt);
3426 uint32_t base = unionArrays[0][i].getUConst();
3427 uint32_t insert = unionArrays[1][i].getUConst();
3428 resultArray[i].setUConst((base & baseMask) |
3429 ((insert << offset) & insertMask));
3430 }
3431 }
3432 }
3433 break;
3434 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003435
3436 default:
3437 UNREACHABLE();
3438 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303439 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003440 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303441}
3442
Jamie Madill45bcc782016-11-07 13:58:48 -05003443} // namespace sh