blob: d05508e0294c92e94193895d689e86418574e58e [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"
Jamie Madillb1a85f42014-08-19 15:23:24 -040021#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040023#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040024
Jamie Madill45bcc782016-11-07 13:58:48 -050025namespace sh
26{
27
Jamie Madillb1a85f42014-08-19 15:23:24 -040028namespace
29{
30
Jamie Madilld7b1ab52016-12-12 14:42:19 -050031const float kPi = 3.14159265358979323846f;
Arun Patole9dea48f2015-04-02 11:45:09 +053032const float kDegreesToRadiansMultiplier = kPi / 180.0f;
33const float kRadiansToDegreesMultiplier = 180.0f / kPi;
34
Jamie Madillb1a85f42014-08-19 15:23:24 -040035TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
36{
37 return left > right ? left : right;
38}
39
Arun Patole274f0702015-05-05 13:33:30 +053040TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
41{
42 TConstantUnion *constUnion = new TConstantUnion[size];
43 for (unsigned int i = 0; i < size; ++i)
Jamie Madilld7b1ab52016-12-12 14:42:19 -050044 constUnion[i] = constant;
Arun Patole274f0702015-05-05 13:33:30 +053045
46 return constUnion;
47}
48
Olli Etuahof119a262016-08-19 15:54:22 +030049void UndefinedConstantFoldingError(const TSourceLoc &loc,
50 TOperator op,
51 TBasicType basicType,
52 TDiagnostics *diagnostics,
53 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053054{
Olli Etuahof119a262016-08-19 15:54:22 +030055 diagnostics->warning(loc, "operation result is undefined for the values passed in",
Olli Etuaho4de340a2016-12-16 09:32:03 +000056 GetOperatorString(op));
Arun Patolebf790422015-05-18 17:53:04 +053057
58 switch (basicType)
59 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050060 case EbtFloat:
61 result->setFConst(0.0f);
62 break;
63 case EbtInt:
64 result->setIConst(0);
65 break;
66 case EbtUInt:
67 result->setUConst(0u);
68 break;
69 case EbtBool:
70 result->setBConst(false);
71 break;
72 default:
73 break;
Arun Patolebf790422015-05-18 17:53:04 +053074 }
75}
76
Olli Etuaho5c0e0232015-11-11 15:55:59 +020077float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053078{
79 float result = 0.0f;
80 for (size_t i = 0; i < paramArraySize; i++)
81 {
82 float f = paramArray[i].getFConst();
83 result += f * f;
84 }
85 return sqrtf(result);
86}
87
Olli Etuaho5c0e0232015-11-11 15:55:59 +020088float VectorDotProduct(const TConstantUnion *paramArray1,
89 const TConstantUnion *paramArray2,
90 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053091{
92 float result = 0.0f;
93 for (size_t i = 0; i < paramArraySize; i++)
94 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
95 return result;
96}
97
Olli Etuaho2768bc82017-12-12 11:51:48 +020098TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray, const TIntermTyped *originalNode)
Olli Etuahob43846e2015-06-02 18:18:57 +030099{
Olli Etuaho2768bc82017-12-12 11:51:48 +0200100 ASSERT(constArray != nullptr);
101 // Note that we inherit whatever qualifier the folded node had. Nodes may be constant folded
102 // without being qualified as constant.
Olli Etuahob43846e2015-06-02 18:18:57 +0300103 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuahob43846e2015-06-02 18:18:57 +0300104 folded->setLine(originalNode->getLine());
105 return folded;
106}
107
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200108angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
109 const unsigned int &rows,
110 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530111{
112 std::vector<float> elements;
113 for (size_t i = 0; i < rows * cols; i++)
114 elements.push_back(paramArray[i].getFConst());
115 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300116 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
117 // so that the created matrix will have the expected dimensions after the transpose.
118 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530119}
120
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200121angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530122{
123 std::vector<float> elements;
124 for (size_t i = 0; i < size * size; i++)
125 elements.push_back(paramArray[i].getFConst());
126 // Transpose is used since the Matrix constructor expects arguments in row-major order,
127 // whereas the paramArray is in column-major order.
128 return angle::Matrix<float>(elements, size).transpose();
129}
130
131void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
132{
133 // Transpose is used since the input Matrix is in row-major order,
134 // whereas the actual result should be in column-major order.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500135 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530136 std::vector<float> resultElements = result.elements();
137 for (size_t i = 0; i < resultElements.size(); i++)
138 resultArray[i].setFConst(resultElements[i]);
139}
140
Olli Etuaho765924f2018-01-04 12:48:36 +0200141bool CanFoldAggregateBuiltInOp(TOperator op)
142{
143 switch (op)
144 {
145 case EOpAtan:
146 case EOpPow:
147 case EOpMod:
148 case EOpMin:
149 case EOpMax:
150 case EOpClamp:
151 case EOpMix:
152 case EOpStep:
153 case EOpSmoothStep:
154 case EOpLdexp:
155 case EOpMulMatrixComponentWise:
156 case EOpOuterProduct:
157 case EOpEqualComponentWise:
158 case EOpNotEqualComponentWise:
159 case EOpLessThanComponentWise:
160 case EOpLessThanEqualComponentWise:
161 case EOpGreaterThanComponentWise:
162 case EOpGreaterThanEqualComponentWise:
163 case EOpDistance:
164 case EOpDot:
165 case EOpCross:
166 case EOpFaceforward:
167 case EOpReflect:
168 case EOpRefract:
169 case EOpBitfieldExtract:
170 case EOpBitfieldInsert:
171 return true;
172 default:
173 return false;
174 }
175}
176
Jamie Madillb1a85f42014-08-19 15:23:24 -0400177} // namespace anonymous
178
Jamie Madillb1a85f42014-08-19 15:23:24 -0400179////////////////////////////////////////////////////////////////
180//
181// Member functions of the nodes used for building the tree.
182//
183////////////////////////////////////////////////////////////////
184
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200185TIntermExpression::TIntermExpression(const TType &t) : TIntermTyped(), mType(t)
186{
187}
188
189void TIntermExpression::setTypePreservePrecision(const TType &t)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300190{
191 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500192 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300193 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
194 mType.setPrecision(precision);
195}
196
Jamie Madillb1a85f42014-08-19 15:23:24 -0400197#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500198 if (node == original) \
199 { \
200 node = static_cast<type *>(replacement); \
201 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400202 }
203
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500204bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400205{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300206 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400207 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
208 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
209 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100210 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400211 return false;
212}
213
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500214bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400215{
216 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
217 return false;
218}
219
Olli Etuahob6fa0432016-09-28 16:28:05 +0100220bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
221{
222 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
223 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
224 return false;
225}
226
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500227bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400228{
229 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
230 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
231 return false;
232}
233
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500234bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400235{
Olli Etuahoa2234302016-08-31 12:05:39 +0300236 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400237 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
238 return false;
239}
240
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000241bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
242{
243 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
244 return false;
245}
246
Olli Etuaho336b1472016-10-05 16:37:55 +0100247bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
248{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000249 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100250 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
251 return false;
252}
253
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500254bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400255{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100256 return replaceChildNodeInternal(original, replacement);
257}
258
259bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
260{
261 return replaceChildNodeInternal(original, replacement);
262}
263
Olli Etuaho16c745a2017-01-16 17:02:27 +0000264bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
265{
266 return replaceChildNodeInternal(original, replacement);
267}
268
Olli Etuaho13389b62016-10-16 11:48:18 +0100269bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
270{
271 return replaceChildNodeInternal(original, replacement);
272}
273
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100274bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
275{
276 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400277 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100278 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400279 }
280 return false;
281}
282
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100283bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
284 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300285{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100286 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300287 {
288 if (*it == original)
289 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100290 it = getSequence()->erase(it);
291 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300292 return true;
293 }
294 }
295 return false;
296}
297
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100298bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
299 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300300{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100301 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300302 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300303 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300304 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100305 auto it = getSequence()->begin() + position;
306 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300307 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300308}
309
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200310TIntermSymbol::TIntermSymbol(const TVariable *variable) : TIntermTyped(), mVariable(variable)
Olli Etuaho195be942017-12-04 23:40:14 +0200311{
Olli Etuaho195be942017-12-04 23:40:14 +0200312}
313
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200314bool TIntermSymbol::hasConstantValue() const
315{
316 return variable().getConstPointer() != nullptr;
317}
318
319const TConstantUnion *TIntermSymbol::getConstantValue() const
320{
321 return variable().getConstPointer();
322}
323
Olli Etuahob6af22b2017-12-15 14:05:44 +0200324const TSymbolUniqueId &TIntermSymbol::uniqueId() const
325{
326 return mVariable->uniqueId();
327}
328
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200329const TString &TIntermSymbol::getName() const
330{
331 return mVariable->name();
332}
333
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200334const TType &TIntermSymbol::getType() const
335{
336 return mVariable->getType();
337}
338
Olli Etuahofe486322017-03-21 09:30:54 +0000339TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
340 TIntermSequence *arguments)
341{
Olli Etuaho0c371002017-12-13 17:00:25 +0400342 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000343}
344
Olli Etuaho0c371002017-12-13 17:00:25 +0400345TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
346 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000347{
Olli Etuaho0c371002017-12-13 17:00:25 +0400348 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000349}
350
351TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
352 TIntermSequence *arguments)
353{
354 TIntermAggregate *callNode =
Olli Etuaho0c371002017-12-13 17:00:25 +0400355 new TIntermAggregate(&func, func.getReturnType(), EOpCallBuiltInFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000356 // Note that name needs to be set before texture function type is determined.
357 callNode->setBuiltInFunctionPrecision();
358 return callNode;
359}
360
361TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000362 TIntermSequence *arguments)
363{
Olli Etuaho0c371002017-12-13 17:00:25 +0400364 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000365}
366
367TIntermAggregate *TIntermAggregate::Create(const TType &type,
368 TOperator op,
369 TIntermSequence *arguments)
370{
Olli Etuahofe486322017-03-21 09:30:54 +0000371 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400372 ASSERT(op != EOpCallInternalRawFunction); // Should use CreateRawFunctionCall
Olli Etuahofe486322017-03-21 09:30:54 +0000373 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400374 ASSERT(op != EOpConstruct); // Should use CreateConstructor
375 return new TIntermAggregate(nullptr, type, op, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000376}
377
Olli Etuaho0c371002017-12-13 17:00:25 +0400378TIntermAggregate::TIntermAggregate(const TFunction *func,
379 const TType &type,
380 TOperator op,
381 TIntermSequence *arguments)
382 : TIntermOperator(op),
383 mUseEmulatedFunction(false),
384 mGotPrecisionFromChildren(false),
385 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800386{
387 if (arguments != nullptr)
388 {
389 mArguments.swap(*arguments);
390 }
Olli Etuaho1bb85282017-12-14 13:39:53 +0200391 ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800392 setTypePrecisionAndQualifier(type);
393}
394
395void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
396{
397 setType(type);
398 mType.setQualifier(EvqTemporary);
399 if (!isFunctionCall())
400 {
401 if (isConstructor())
402 {
403 // Structs should not be precision qualified, the individual members may be.
404 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300405 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800406 {
407 setPrecisionFromChildren();
408 }
409 }
410 else
411 {
412 setPrecisionForBuiltInOp();
413 }
414 if (areChildrenConstQualified())
415 {
416 mType.setQualifier(EvqConst);
417 }
418 }
419}
420
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200421bool TIntermAggregate::areChildrenConstQualified()
422{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800423 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200424 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800425 TIntermTyped *typedArg = arg->getAsTyped();
426 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200427 {
428 return false;
429 }
430 }
431 return true;
432}
433
Olli Etuahod2a67b92014-10-21 16:42:57 +0300434void TIntermAggregate::setPrecisionFromChildren()
435{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300436 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300437 if (getBasicType() == EbtBool)
438 {
439 mType.setPrecision(EbpUndefined);
440 return;
441 }
442
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500443 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800444 TIntermSequence::iterator childIter = mArguments.begin();
445 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300446 {
447 TIntermTyped *typed = (*childIter)->getAsTyped();
448 if (typed)
449 precision = GetHigherPrecision(typed->getPrecision(), precision);
450 ++childIter;
451 }
452 mType.setPrecision(precision);
453}
454
Olli Etuaho9250cb22017-01-21 10:51:27 +0000455void TIntermAggregate::setPrecisionForBuiltInOp()
456{
457 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800458 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000459 if (!setPrecisionForSpecialBuiltInOp())
460 {
461 setPrecisionFromChildren();
462 }
463}
464
465bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
466{
467 switch (mOp)
468 {
469 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800470 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
471 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000472 return true;
473 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800474 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
475 mArguments[1]->getAsTyped()->getPrecision()));
476 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000477 return true;
478 case EOpUaddCarry:
479 case EOpUsubBorrow:
480 mType.setPrecision(EbpHigh);
481 return true;
482 default:
483 return false;
484 }
485}
486
Olli Etuahod2a67b92014-10-21 16:42:57 +0300487void TIntermAggregate::setBuiltInFunctionPrecision()
488{
489 // All built-ins returning bool should be handled as ops, not functions.
490 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800491 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300492
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800493 TPrecision precision = EbpUndefined;
494 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300495 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800496 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300497 // ESSL spec section 8: texture functions get their precision from the sampler.
498 if (typed && IsSampler(typed->getBasicType()))
499 {
500 precision = typed->getPrecision();
501 break;
502 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300503 }
504 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
505 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobed35d72017-12-20 16:36:26 +0200506 if (mFunction->name().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300507 mType.setPrecision(EbpHigh);
508 else
509 mType.setPrecision(precision);
510}
511
Olli Etuahof2209f72017-04-01 12:45:55 +0300512TString TIntermAggregate::getSymbolTableMangledName() const
513{
514 ASSERT(!isConstructor());
515 switch (mOp)
516 {
517 case EOpCallInternalRawFunction:
518 case EOpCallBuiltInFunction:
519 case EOpCallFunctionInAST:
Olli Etuahobed35d72017-12-20 16:36:26 +0200520 return TFunction::GetMangledNameFromCall(mFunction->name(), mArguments);
Olli Etuahof2209f72017-04-01 12:45:55 +0300521 default:
522 TString opString = GetOperatorString(mOp);
523 return TFunction::GetMangledNameFromCall(opString, mArguments);
524 }
525}
526
Olli Etuaho0c371002017-12-13 17:00:25 +0400527const char *TIntermAggregate::functionName() const
528{
529 ASSERT(!isConstructor());
530 switch (mOp)
531 {
532 case EOpCallInternalRawFunction:
533 case EOpCallBuiltInFunction:
534 case EOpCallFunctionInAST:
Olli Etuahobed35d72017-12-20 16:36:26 +0200535 return mFunction->name().c_str();
Olli Etuaho0c371002017-12-13 17:00:25 +0400536 default:
537 return GetOperatorString(mOp);
538 }
539}
540
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200541bool TIntermAggregate::hasConstantValue() const
542{
543 if (!isConstructor())
544 {
545 return false;
546 }
547 for (TIntermNode *constructorArg : mArguments)
548 {
549 if (!constructorArg->getAsTyped()->hasConstantValue())
550 {
551 return false;
552 }
553 }
554 return true;
555}
556
557const TConstantUnion *TIntermAggregate::getConstantValue() const
558{
559 if (!hasConstantValue())
560 {
561 return nullptr;
562 }
563 ASSERT(isConstructor());
564 ASSERT(mArguments.size() > 0u);
565
566 TConstantUnion *constArray = nullptr;
567 if (isArray())
568 {
569 size_t elementSize = mArguments.front()->getAsTyped()->getType().getObjectSize();
570 constArray = new TConstantUnion[elementSize * getOutermostArraySize()];
571
572 size_t elementOffset = 0u;
573 for (TIntermNode *constructorArg : mArguments)
574 {
575 const TConstantUnion *elementConstArray =
576 constructorArg->getAsTyped()->getConstantValue();
577 ASSERT(elementConstArray);
578 size_t elementSizeBytes = sizeof(TConstantUnion) * elementSize;
579 memcpy(static_cast<void *>(&constArray[elementOffset]),
580 static_cast<const void *>(elementConstArray), elementSizeBytes);
581 elementOffset += elementSize;
582 }
583 return constArray;
584 }
585
586 size_t resultSize = getType().getObjectSize();
587 constArray = new TConstantUnion[resultSize];
588 TBasicType basicType = getBasicType();
589
590 size_t resultIndex = 0u;
591
592 if (mArguments.size() == 1u)
593 {
594 TIntermNode *argument = mArguments.front();
595 TIntermTyped *argumentTyped = argument->getAsTyped();
596 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
597 // Check the special case of constructing a matrix diagonal from a single scalar,
598 // or a vector from a single scalar.
599 if (argumentTyped->getType().getObjectSize() == 1u)
600 {
601 if (isMatrix())
602 {
603 int resultCols = getType().getCols();
604 int resultRows = getType().getRows();
605 for (int col = 0; col < resultCols; ++col)
606 {
607 for (int row = 0; row < resultRows; ++row)
608 {
609 if (col == row)
610 {
611 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
612 }
613 else
614 {
615 constArray[resultIndex].setFConst(0.0f);
616 }
617 ++resultIndex;
618 }
619 }
620 }
621 else
622 {
623 while (resultIndex < resultSize)
624 {
625 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
626 ++resultIndex;
627 }
628 }
629 ASSERT(resultIndex == resultSize);
630 return constArray;
631 }
632 else if (isMatrix() && argumentTyped->isMatrix())
633 {
634 // The special case of constructing a matrix from a matrix.
635 int argumentCols = argumentTyped->getType().getCols();
636 int argumentRows = argumentTyped->getType().getRows();
637 int resultCols = getType().getCols();
638 int resultRows = getType().getRows();
639 for (int col = 0; col < resultCols; ++col)
640 {
641 for (int row = 0; row < resultRows; ++row)
642 {
643 if (col < argumentCols && row < argumentRows)
644 {
645 constArray[resultIndex].cast(
646 basicType, argumentConstantValue[col * argumentRows + row]);
647 }
648 else if (col == row)
649 {
650 constArray[resultIndex].setFConst(1.0f);
651 }
652 else
653 {
654 constArray[resultIndex].setFConst(0.0f);
655 }
656 ++resultIndex;
657 }
658 }
659 ASSERT(resultIndex == resultSize);
660 return constArray;
661 }
662 }
663
664 for (TIntermNode *argument : mArguments)
665 {
666 TIntermTyped *argumentTyped = argument->getAsTyped();
667 size_t argumentSize = argumentTyped->getType().getObjectSize();
668 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
669 for (size_t i = 0u; i < argumentSize; ++i)
670 {
671 if (resultIndex >= resultSize)
672 break;
673 constArray[resultIndex].cast(basicType, argumentConstantValue[i]);
674 ++resultIndex;
675 }
676 }
677 ASSERT(resultIndex == resultSize);
678 return constArray;
679}
680
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300681bool TIntermAggregate::hasSideEffects() const
682{
Olli Etuahoea78d2b2018-01-09 12:55:27 +0200683 if (getQualifier() == EvqConst)
684 {
685 return false;
686 }
687 bool calledFunctionHasNoSideEffects =
688 isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects();
689 if (calledFunctionHasNoSideEffects || isConstructor())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300690 {
691 for (TIntermNode *arg : mArguments)
692 {
693 if (arg->getAsTyped()->hasSideEffects())
694 {
695 return true;
696 }
697 }
698 return false;
699 }
700 // Conservatively assume most aggregate operators have side-effects
701 return true;
702}
703
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100704void TIntermBlock::appendStatement(TIntermNode *statement)
705{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300706 // Declaration nodes with no children can appear if it was an empty declaration or if all the
707 // declarators just added constants to the symbol table instead of generating code. We still
708 // need to add the declaration to the AST in that case because it might be relevant to the
709 // validity of switch/case.
710 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100711 {
712 mStatements.push_back(statement);
713 }
714}
715
Olli Etuaho16c745a2017-01-16 17:02:27 +0000716void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
717{
718 ASSERT(parameter != nullptr);
719 mParameters.push_back(parameter);
720}
721
Olli Etuaho13389b62016-10-16 11:48:18 +0100722void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
723{
724 ASSERT(declarator != nullptr);
725 ASSERT(declarator->getAsSymbolNode() != nullptr ||
726 (declarator->getAsBinaryNode() != nullptr &&
727 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
728 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300729 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100730 mDeclarators.push_back(declarator);
731}
732
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300733bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
734{
735 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
736 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
737 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
738 return false;
739}
740
Olli Etuaho57961272016-09-14 13:57:46 +0300741bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400742{
743 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100744 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
745 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400746 return false;
747}
748
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500749bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200750{
751 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100752 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300753 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200754 return false;
755}
756
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500757bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200758{
759 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
760 return false;
761}
762
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200763TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode()
Olli Etuahod7a25242015-08-18 13:49:45 +0300764{
765 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
766 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200767 // We need to manually copy any fields of TIntermNode.
Olli Etuahod7a25242015-08-18 13:49:45 +0300768 mLine = node.mLine;
769}
770
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200771bool TIntermTyped::hasConstantValue() const
Olli Etuahod4f4c112016-04-15 15:11:24 +0300772{
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200773 return false;
774}
775
776const TConstantUnion *TIntermTyped::getConstantValue() const
777{
778 return nullptr;
Olli Etuahod4f4c112016-04-15 15:11:24 +0300779}
780
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200781TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node)
782 : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300783{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200784 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300785}
786
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200787TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200788 : TIntermTyped(), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100789{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200790 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100791}
792
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200793const TType &TIntermFunctionPrototype::getType() const
794{
795 return mFunction->getReturnType();
796}
797
Olli Etuahod7a25242015-08-18 13:49:45 +0300798TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
799 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300800 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100801 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400802 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300803{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800804 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300805 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800806 TIntermTyped *typedArg = arg->getAsTyped();
807 ASSERT(typedArg != nullptr);
808 TIntermTyped *argCopy = typedArg->deepCopy();
809 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300810 }
811}
812
Olli Etuahofe486322017-03-21 09:30:54 +0000813TIntermAggregate *TIntermAggregate::shallowCopy() const
814{
815 TIntermSequence *copySeq = new TIntermSequence();
816 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400817 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000818 copyNode->setLine(mLine);
819 return copyNode;
820}
821
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200822TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermExpression(node)
Olli Etuahob6fa0432016-09-28 16:28:05 +0100823{
824 TIntermTyped *operandCopy = node.mOperand->deepCopy();
825 ASSERT(operandCopy != nullptr);
826 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000827 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100828}
829
Olli Etuahod7a25242015-08-18 13:49:45 +0300830TIntermBinary::TIntermBinary(const TIntermBinary &node)
831 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
832{
833 TIntermTyped *leftCopy = node.mLeft->deepCopy();
834 TIntermTyped *rightCopy = node.mRight->deepCopy();
835 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
836 mLeft = leftCopy;
837 mRight = rightCopy;
838}
839
840TIntermUnary::TIntermUnary(const TIntermUnary &node)
841 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
842{
843 TIntermTyped *operandCopy = node.mOperand->deepCopy();
844 ASSERT(operandCopy != nullptr);
845 mOperand = operandCopy;
846}
847
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200848TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300849{
Olli Etuahod7a25242015-08-18 13:49:45 +0300850 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300851 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
852 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300853 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300854 mCondition = conditionCopy;
855 mTrueExpression = trueCopy;
856 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300857}
858
Jamie Madillb1a85f42014-08-19 15:23:24 -0400859bool TIntermOperator::isAssignment() const
860{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300861 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400862}
863
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300864bool TIntermOperator::isMultiplication() const
865{
866 switch (mOp)
867 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500868 case EOpMul:
869 case EOpMatrixTimesMatrix:
870 case EOpMatrixTimesVector:
871 case EOpMatrixTimesScalar:
872 case EOpVectorTimesMatrix:
873 case EOpVectorTimesScalar:
874 return true;
875 default:
876 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300877 }
878}
879
Jamie Madillb1a85f42014-08-19 15:23:24 -0400880bool TIntermOperator::isConstructor() const
881{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300882 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400883}
884
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800885bool TIntermOperator::isFunctionCall() const
886{
887 switch (mOp)
888 {
889 case EOpCallFunctionInAST:
890 case EOpCallBuiltInFunction:
891 case EOpCallInternalRawFunction:
892 return true;
893 default:
894 return false;
895 }
896}
897
Olli Etuaho1dded802016-08-18 18:13:13 +0300898TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
899{
900 if (left.isMatrix())
901 {
902 if (right.isMatrix())
903 {
904 return EOpMatrixTimesMatrix;
905 }
906 else
907 {
908 if (right.isVector())
909 {
910 return EOpMatrixTimesVector;
911 }
912 else
913 {
914 return EOpMatrixTimesScalar;
915 }
916 }
917 }
918 else
919 {
920 if (right.isMatrix())
921 {
922 if (left.isVector())
923 {
924 return EOpVectorTimesMatrix;
925 }
926 else
927 {
928 return EOpMatrixTimesScalar;
929 }
930 }
931 else
932 {
933 // Neither operand is a matrix.
934 if (left.isVector() == right.isVector())
935 {
936 // Leave as component product.
937 return EOpMul;
938 }
939 else
940 {
941 return EOpVectorTimesScalar;
942 }
943 }
944 }
945}
946
947TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
948{
949 if (left.isMatrix())
950 {
951 if (right.isMatrix())
952 {
953 return EOpMatrixTimesMatrixAssign;
954 }
955 else
956 {
957 // right should be scalar, but this may not be validated yet.
958 return EOpMatrixTimesScalarAssign;
959 }
960 }
961 else
962 {
963 if (right.isMatrix())
964 {
965 // Left should be a vector, but this may not be validated yet.
966 return EOpVectorTimesMatrixAssign;
967 }
968 else
969 {
970 // Neither operand is a matrix.
971 if (left.isVector() == right.isVector())
972 {
973 // Leave as component product.
974 return EOpMulAssign;
975 }
976 else
977 {
978 // left should be vector and right should be scalar, but this may not be validated
979 // yet.
980 return EOpVectorTimesScalarAssign;
981 }
982 }
983 }
984}
985
Jamie Madillb1a85f42014-08-19 15:23:24 -0400986//
987// Make sure the type of a unary operator is appropriate for its
988// combination of operation and operand type.
989//
Olli Etuahoa2234302016-08-31 12:05:39 +0300990void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400991{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300992 if (mOp == EOpArrayLength)
993 {
994 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
995 setType(TType(EbtInt, EbpUndefined, EvqConst));
996 return;
997 }
998
Olli Etuahoa2234302016-08-31 12:05:39 +0300999 TQualifier resultQualifier = EvqTemporary;
1000 if (mOperand->getQualifier() == EvqConst)
1001 resultQualifier = EvqConst;
1002
1003 unsigned char operandPrimarySize =
1004 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001005 switch (mOp)
1006 {
Olli Etuahoa2234302016-08-31 12:05:39 +03001007 case EOpFloatBitsToInt:
1008 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
1009 break;
1010 case EOpFloatBitsToUint:
1011 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
1012 break;
1013 case EOpIntBitsToFloat:
1014 case EOpUintBitsToFloat:
1015 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
1016 break;
1017 case EOpPackSnorm2x16:
1018 case EOpPackUnorm2x16:
1019 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001020 case EOpPackUnorm4x8:
1021 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +03001022 setType(TType(EbtUInt, EbpHigh, resultQualifier));
1023 break;
1024 case EOpUnpackSnorm2x16:
1025 case EOpUnpackUnorm2x16:
1026 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
1027 break;
1028 case EOpUnpackHalf2x16:
1029 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
1030 break;
Olli Etuaho25aef452017-01-29 16:15:44 -08001031 case EOpUnpackUnorm4x8:
1032 case EOpUnpackSnorm4x8:
1033 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
1034 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001035 case EOpAny:
1036 case EOpAll:
1037 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1038 break;
1039 case EOpLength:
1040 case EOpDeterminant:
1041 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
1042 break;
1043 case EOpTranspose:
1044 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
1045 static_cast<unsigned char>(mOperand->getType().getRows()),
1046 static_cast<unsigned char>(mOperand->getType().getCols())));
1047 break;
1048 case EOpIsInf:
1049 case EOpIsNan:
1050 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
1051 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001052 case EOpBitfieldReverse:
1053 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
1054 break;
1055 case EOpBitCount:
1056 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1057 break;
1058 case EOpFindLSB:
1059 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1060 break;
1061 case EOpFindMSB:
1062 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1063 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001064 default:
1065 setType(mOperand->getType());
1066 mType.setQualifier(resultQualifier);
1067 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001068 }
Olli Etuahoa2234302016-08-31 12:05:39 +03001069}
Jamie Madillb1a85f42014-08-19 15:23:24 -04001070
Olli Etuahob6fa0432016-09-28 16:28:05 +01001071TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001072 : TIntermExpression(TType(EbtFloat, EbpUndefined)),
Olli Etuahob6fa0432016-09-28 16:28:05 +01001073 mOperand(operand),
1074 mSwizzleOffsets(swizzleOffsets)
1075{
1076 ASSERT(mSwizzleOffsets.size() <= 4);
1077 promote();
1078}
1079
Olli Etuahoa2234302016-08-31 12:05:39 +03001080TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
1081 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
1082{
1083 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001084}
1085
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001086TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1087 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
1088{
1089 promote();
1090}
1091
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001092TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1093 : TIntermNode(), mSymbol(symbol)
1094{
1095 ASSERT(symbol);
1096 setLine(line);
1097}
1098
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001099TIntermTernary::TIntermTernary(TIntermTyped *cond,
1100 TIntermTyped *trueExpression,
1101 TIntermTyped *falseExpression)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001102 : TIntermExpression(trueExpression->getType()),
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001103 mCondition(cond),
1104 mTrueExpression(trueExpression),
1105 mFalseExpression(falseExpression)
1106{
1107 getTypePointer()->setQualifier(
1108 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1109}
1110
Olli Etuaho81629262017-04-19 11:56:01 +03001111TIntermLoop::TIntermLoop(TLoopType type,
1112 TIntermNode *init,
1113 TIntermTyped *cond,
1114 TIntermTyped *expr,
1115 TIntermBlock *body)
1116 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1117{
1118 // Declaration nodes with no children can appear if all the declarators just added constants to
1119 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1120 if (mInit && mInit->getAsDeclarationNode() &&
1121 mInit->getAsDeclarationNode()->getSequence()->empty())
1122 {
1123 mInit = nullptr;
1124 }
1125}
1126
Olli Etuaho923ecef2017-10-11 12:01:38 +03001127TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
1128 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
1129{
1130 // Prune empty false blocks so that there won't be unnecessary operations done on it.
1131 if (mFalseBlock && mFalseBlock->getSequence()->empty())
1132 {
1133 mFalseBlock = nullptr;
1134 }
1135}
1136
1137TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
1138 : TIntermNode(), mInit(init), mStatementList(statementList)
1139{
1140 ASSERT(mStatementList);
1141}
1142
1143void TIntermSwitch::setStatementList(TIntermBlock *statementList)
1144{
1145 ASSERT(statementList);
1146 mStatementList = statementList;
1147}
1148
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001149// static
1150TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1151 TIntermTyped *trueExpression,
1152 TIntermTyped *falseExpression)
1153{
1154 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1155 falseExpression->getQualifier() == EvqConst)
1156 {
1157 return EvqConst;
1158 }
1159 return EvqTemporary;
1160}
1161
Olli Etuaho765924f2018-01-04 12:48:36 +02001162TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001163{
1164 if (mCondition->getAsConstantUnion())
1165 {
1166 if (mCondition->getAsConstantUnion()->getBConst(0))
1167 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001168 return mTrueExpression;
1169 }
1170 else
1171 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001172 return mFalseExpression;
1173 }
1174 }
1175 return this;
1176}
1177
Olli Etuahob6fa0432016-09-28 16:28:05 +01001178void TIntermSwizzle::promote()
1179{
1180 TQualifier resultQualifier = EvqTemporary;
1181 if (mOperand->getQualifier() == EvqConst)
1182 resultQualifier = EvqConst;
1183
1184 auto numFields = mSwizzleOffsets.size();
1185 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1186 static_cast<unsigned char>(numFields)));
1187}
1188
1189bool TIntermSwizzle::hasDuplicateOffsets() const
1190{
1191 int offsetCount[4] = {0u, 0u, 0u, 0u};
1192 for (const auto offset : mSwizzleOffsets)
1193 {
1194 offsetCount[offset]++;
1195 if (offsetCount[offset] > 1)
1196 {
1197 return true;
1198 }
1199 }
1200 return false;
1201}
1202
Olli Etuaho09b04a22016-12-15 13:30:26 +00001203bool TIntermSwizzle::offsetsMatch(int offset) const
1204{
1205 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1206}
1207
Olli Etuahob6fa0432016-09-28 16:28:05 +01001208void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1209{
1210 for (const int offset : mSwizzleOffsets)
1211 {
1212 switch (offset)
1213 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001214 case 0:
1215 *out << "x";
1216 break;
1217 case 1:
1218 *out << "y";
1219 break;
1220 case 2:
1221 *out << "z";
1222 break;
1223 case 3:
1224 *out << "w";
1225 break;
1226 default:
1227 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001228 }
1229 }
1230}
1231
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001232TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1233 const TIntermTyped *left,
1234 const TIntermTyped *right)
1235{
1236 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1237 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1238 right->getQualifier() != EvqConst)
1239 {
1240 return EvqTemporary;
1241 }
1242 return EvqConst;
1243}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001244
1245// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001246void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001247{
Olli Etuaho1dded802016-08-18 18:13:13 +03001248 ASSERT(!isMultiplication() ||
1249 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1250
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001251 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1252 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001253 if (mOp == EOpComma)
1254 {
1255 setType(mRight->getType());
1256 return;
1257 }
1258
Jamie Madillb1a85f42014-08-19 15:23:24 -04001259 // Base assumption: just make the type the same as the left
1260 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001261 setType(mLeft->getType());
1262
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001263 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001264 // Binary operations results in temporary variables unless both
1265 // operands are const.
1266 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1267 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001268 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001269 getTypePointer()->setQualifier(EvqTemporary);
1270 }
1271
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001272 // Handle indexing ops.
1273 switch (mOp)
1274 {
1275 case EOpIndexDirect:
1276 case EOpIndexIndirect:
1277 if (mLeft->isArray())
1278 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001279 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001280 }
1281 else if (mLeft->isMatrix())
1282 {
1283 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1284 static_cast<unsigned char>(mLeft->getRows())));
1285 }
1286 else if (mLeft->isVector())
1287 {
1288 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1289 }
1290 else
1291 {
1292 UNREACHABLE();
1293 }
1294 return;
1295 case EOpIndexDirectStruct:
1296 {
1297 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1298 const int i = mRight->getAsConstantUnion()->getIConst(0);
1299 setType(*fields[i]->type());
1300 getTypePointer()->setQualifier(resultQualifier);
1301 return;
1302 }
1303 case EOpIndexDirectInterfaceBlock:
1304 {
1305 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1306 const int i = mRight->getAsConstantUnion()->getIConst(0);
1307 setType(*fields[i]->type());
1308 getTypePointer()->setQualifier(resultQualifier);
1309 return;
1310 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001311 default:
1312 break;
1313 }
1314
1315 ASSERT(mLeft->isArray() == mRight->isArray());
1316
1317 // The result gets promoted to the highest precision.
1318 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1319 getTypePointer()->setPrecision(higherPrecision);
1320
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001321 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001322
1323 //
1324 // All scalars or structs. Code after this test assumes this case is removed!
1325 //
1326 if (nominalSize == 1)
1327 {
1328 switch (mOp)
1329 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001330 //
1331 // Promote to conditional
1332 //
1333 case EOpEqual:
1334 case EOpNotEqual:
1335 case EOpLessThan:
1336 case EOpGreaterThan:
1337 case EOpLessThanEqual:
1338 case EOpGreaterThanEqual:
1339 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1340 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001341
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001342 //
1343 // And and Or operate on conditionals
1344 //
1345 case EOpLogicalAnd:
1346 case EOpLogicalXor:
1347 case EOpLogicalOr:
1348 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1349 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1350 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001351
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001352 default:
1353 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001354 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001355 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001356 }
1357
1358 // If we reach here, at least one of the operands is vector or matrix.
1359 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001360 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001361
Jamie Madillb1a85f42014-08-19 15:23:24 -04001362 switch (mOp)
1363 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001364 case EOpMul:
1365 break;
1366 case EOpMatrixTimesScalar:
1367 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001368 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001369 setType(TType(basicType, higherPrecision, resultQualifier,
1370 static_cast<unsigned char>(mRight->getCols()),
1371 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001372 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001373 break;
1374 case EOpMatrixTimesVector:
1375 setType(TType(basicType, higherPrecision, resultQualifier,
1376 static_cast<unsigned char>(mLeft->getRows()), 1));
1377 break;
1378 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001379 setType(TType(basicType, higherPrecision, resultQualifier,
1380 static_cast<unsigned char>(mRight->getCols()),
1381 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001382 break;
1383 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001384 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001385 static_cast<unsigned char>(nominalSize), 1));
1386 break;
1387 case EOpVectorTimesMatrix:
1388 setType(TType(basicType, higherPrecision, resultQualifier,
1389 static_cast<unsigned char>(mRight->getCols()), 1));
1390 break;
1391 case EOpMulAssign:
1392 case EOpVectorTimesScalarAssign:
1393 case EOpVectorTimesMatrixAssign:
1394 case EOpMatrixTimesScalarAssign:
1395 case EOpMatrixTimesMatrixAssign:
1396 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1397 break;
1398 case EOpAssign:
1399 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001400 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1401 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1402 break;
1403 case EOpAdd:
1404 case EOpSub:
1405 case EOpDiv:
1406 case EOpIMod:
1407 case EOpBitShiftLeft:
1408 case EOpBitShiftRight:
1409 case EOpBitwiseAnd:
1410 case EOpBitwiseXor:
1411 case EOpBitwiseOr:
1412 case EOpAddAssign:
1413 case EOpSubAssign:
1414 case EOpDivAssign:
1415 case EOpIModAssign:
1416 case EOpBitShiftLeftAssign:
1417 case EOpBitShiftRightAssign:
1418 case EOpBitwiseAndAssign:
1419 case EOpBitwiseXorAssign:
1420 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001421 {
1422 const int secondarySize =
1423 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1424 setType(TType(basicType, higherPrecision, resultQualifier,
1425 static_cast<unsigned char>(nominalSize),
1426 static_cast<unsigned char>(secondarySize)));
1427 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001428 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001429 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001430 case EOpEqual:
1431 case EOpNotEqual:
1432 case EOpLessThan:
1433 case EOpGreaterThan:
1434 case EOpLessThanEqual:
1435 case EOpGreaterThanEqual:
1436 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1437 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001438 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001439 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001440
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001441 case EOpIndexDirect:
1442 case EOpIndexIndirect:
1443 case EOpIndexDirectInterfaceBlock:
1444 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001445 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001446 UNREACHABLE();
1447 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001448 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001449 UNREACHABLE();
1450 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001451 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001452}
1453
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001454bool TIntermConstantUnion::hasConstantValue() const
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001455{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001456 return true;
1457}
1458
1459const TConstantUnion *TIntermConstantUnion::getConstantValue() const
1460{
1461 return mUnionArrayPointer;
1462}
1463
1464const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
1465 const TConstantUnion *constArray,
1466 int index)
1467{
1468 if (type.isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001469 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001470 ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
1471 TType arrayElementType(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001472 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001473 size_t arrayElementSize = arrayElementType.getObjectSize();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001474 return &constArray[arrayElementSize * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001475 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001476 else if (type.isMatrix())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001477 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001478 ASSERT(index < type.getCols());
1479 int size = type.getRows();
1480 return &constArray[size * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001481 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001482 else if (type.isVector())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001483 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001484 ASSERT(index < type.getNominalSize());
1485 return &constArray[index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001486 }
1487 else
1488 {
1489 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001490 return nullptr;
1491 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001492}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001493
Olli Etuaho765924f2018-01-04 12:48:36 +02001494TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001495{
1496 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1497 if (operandConstant == nullptr)
1498 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001499 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001500 }
1501
1502 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1503 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1504 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001505 constArray[i] = *TIntermConstantUnion::FoldIndexing(
1506 operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
Olli Etuahob6fa0432016-09-28 16:28:05 +01001507 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001508 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001509}
1510
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001511TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1512{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001513 const TConstantUnion *rightConstant = mRight->getConstantValue();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001514 switch (mOp)
1515 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001516 case EOpComma:
1517 {
1518 if (mLeft->hasSideEffects())
1519 {
1520 return this;
1521 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001522 return mRight;
1523 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001524 case EOpIndexDirect:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001525 case EOpIndexDirectStruct:
1526 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001527 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001528 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001529 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001530 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001531 size_t index = static_cast<size_t>(rightConstant->getIConst());
1532 TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
1533 if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
1534 !leftAggregate->hasSideEffects())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001535 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001536 ASSERT(index < leftAggregate->getSequence()->size());
1537 // This transformation can't add complexity as we're eliminating the constructor
1538 // entirely.
1539 return leftAggregate->getSequence()->at(index)->getAsTyped();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001540 }
1541
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001542 // If the indexed value is already a constant union, we can't increase duplication of
1543 // data by folding the indexing. Also fold the node in case it's generally beneficial to
1544 // replace this type of node with a constant union even if that would mean duplicating
1545 // data.
1546 if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
1547 {
1548 const TConstantUnion *constantValue = getConstantValue();
1549 if (constantValue == nullptr)
1550 {
1551 return this;
1552 }
1553 return CreateFoldedNode(constantValue, this);
1554 }
1555 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001556 }
1557 case EOpIndexIndirect:
1558 case EOpIndexDirectInterfaceBlock:
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001559 case EOpInitialize:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001560 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001561 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001562 default:
1563 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001564 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001565 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001566 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001567 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001568 const TConstantUnion *leftConstant = mLeft->getConstantValue();
1569 if (leftConstant == nullptr)
1570 {
1571 return this;
1572 }
1573 const TConstantUnion *constArray =
1574 TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
1575 mRight->getType(), diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001576 if (!constArray)
1577 {
1578 return this;
1579 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001580 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001581 }
1582 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001583}
1584
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001585bool TIntermBinary::hasConstantValue() const
1586{
1587 switch (mOp)
1588 {
1589 case EOpIndexDirect:
1590 case EOpIndexDirectStruct:
1591 {
1592 if (mLeft->hasConstantValue() && mRight->hasConstantValue())
1593 {
1594 return true;
1595 }
1596 }
1597 default:
1598 break;
1599 }
1600 return false;
1601}
1602
1603const TConstantUnion *TIntermBinary::getConstantValue() const
1604{
1605 if (!hasConstantValue())
1606 {
1607 return nullptr;
1608 }
1609
1610 const TConstantUnion *leftConstantValue = mLeft->getConstantValue();
1611 int index = mRight->getConstantValue()->getIConst();
1612 const TConstantUnion *constIndexingResult = nullptr;
1613 if (mOp == EOpIndexDirect)
1614 {
1615 constIndexingResult =
1616 TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
1617 }
1618 else
1619 {
1620 ASSERT(mOp == EOpIndexDirectStruct);
1621 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1622
1623 size_t previousFieldsSize = 0;
1624 for (int i = 0; i < index; ++i)
1625 {
1626 previousFieldsSize += fields[i]->type()->getObjectSize();
1627 }
1628 constIndexingResult = leftConstantValue + previousFieldsSize;
1629 }
1630 return constIndexingResult;
1631}
1632
Olli Etuahof119a262016-08-19 15:54:22 +03001633TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001634{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301635 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001636
1637 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301638 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001639 // The size of runtime-sized arrays may only be determined at runtime.
1640 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001641 {
1642 return this;
1643 }
1644 constArray = new TConstantUnion[1];
1645 constArray->setIConst(mOperand->getOutermostArraySize());
1646 }
1647 else
1648 {
1649 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1650 if (operandConstant == nullptr)
1651 {
1652 return this;
1653 }
1654
1655 switch (mOp)
1656 {
1657 case EOpAny:
1658 case EOpAll:
1659 case EOpLength:
1660 case EOpTranspose:
1661 case EOpDeterminant:
1662 case EOpInverse:
1663 case EOpPackSnorm2x16:
1664 case EOpUnpackSnorm2x16:
1665 case EOpPackUnorm2x16:
1666 case EOpUnpackUnorm2x16:
1667 case EOpPackHalf2x16:
1668 case EOpUnpackHalf2x16:
1669 case EOpPackUnorm4x8:
1670 case EOpPackSnorm4x8:
1671 case EOpUnpackUnorm4x8:
1672 case EOpUnpackSnorm4x8:
1673 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1674 break;
1675 default:
1676 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1677 break;
1678 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301679 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001680 if (constArray == nullptr)
1681 {
1682 return this;
1683 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001684 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001685}
1686
Olli Etuahof119a262016-08-19 15:54:22 +03001687TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001688{
1689 // Make sure that all params are constant before actual constant folding.
1690 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001691 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001692 if (param->getAsConstantUnion() == nullptr)
1693 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001694 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001695 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001696 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001697 const TConstantUnion *constArray = nullptr;
Olli Etuaho1d122782015-11-06 15:35:17 +02001698 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001699 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001700 if (mType.canReplaceWithConstantUnion())
Olli Etuaho765924f2018-01-04 12:48:36 +02001701 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001702 constArray = getConstantValue();
Olli Etuaho765924f2018-01-04 12:48:36 +02001703 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001704 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001705 else if (CanFoldAggregateBuiltInOp(mOp))
Olli Etuaho2768bc82017-12-12 11:51:48 +02001706 {
Olli Etuahof119a262016-08-19 15:54:22 +03001707 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001708 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001709 if (constArray == nullptr)
1710 {
1711 return this;
1712 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001713 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001714}
1715
Jamie Madillb1a85f42014-08-19 15:23:24 -04001716//
1717// The fold functions see if an operation on a constant can be done in place,
1718// without generating run-time code.
1719//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001720// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001721//
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001722const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
1723 const TConstantUnion *leftArray,
1724 const TType &leftType,
1725 const TConstantUnion *rightArray,
1726 const TType &rightType,
1727 TDiagnostics *diagnostics,
1728 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001729{
Olli Etuahof119a262016-08-19 15:54:22 +03001730 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001731
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001732 size_t objectSize = leftType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001733
1734 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001735 if (rightType.getObjectSize() == 1 && objectSize > 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001736 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001737 rightArray = Vectorize(*rightArray, objectSize);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001738 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001739 else if (rightType.getObjectSize() > 1 && objectSize == 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001740 {
1741 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001742 leftArray = Vectorize(*leftArray, rightType.getObjectSize());
1743 objectSize = rightType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001744 }
1745
1746 TConstantUnion *resultArray = nullptr;
1747
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001748 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001749 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001750 case EOpAdd:
1751 resultArray = new TConstantUnion[objectSize];
1752 for (size_t i = 0; i < objectSize; i++)
1753 resultArray[i] =
1754 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1755 break;
1756 case EOpSub:
1757 resultArray = new TConstantUnion[objectSize];
1758 for (size_t i = 0; i < objectSize; i++)
1759 resultArray[i] =
1760 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1761 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001762
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001763 case EOpMul:
1764 case EOpVectorTimesScalar:
1765 case EOpMatrixTimesScalar:
1766 resultArray = new TConstantUnion[objectSize];
1767 for (size_t i = 0; i < objectSize; i++)
1768 resultArray[i] =
1769 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1770 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001771
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001772 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001773 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001774 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001775 ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001776
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001777 const int leftCols = leftType.getCols();
1778 const int leftRows = leftType.getRows();
1779 const int rightCols = rightType.getCols();
1780 const int rightRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001781 const int resultCols = rightCols;
1782 const int resultRows = leftRows;
1783
1784 resultArray = new TConstantUnion[resultCols * resultRows];
1785 for (int row = 0; row < resultRows; row++)
1786 {
1787 for (int column = 0; column < resultCols; column++)
1788 {
1789 resultArray[resultRows * column + row].setFConst(0.0f);
1790 for (int i = 0; i < leftCols; i++)
1791 {
1792 resultArray[resultRows * column + row].setFConst(
1793 resultArray[resultRows * column + row].getFConst() +
1794 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001795 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001796 }
1797 }
1798 }
1799 }
1800 break;
1801
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001802 case EOpDiv:
1803 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001804 {
1805 resultArray = new TConstantUnion[objectSize];
1806 for (size_t i = 0; i < objectSize; i++)
1807 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001808 switch (leftType.getBasicType())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001809 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001810 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001811 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001812 ASSERT(op == EOpDiv);
1813 float dividend = leftArray[i].getFConst();
1814 float divisor = rightArray[i].getFConst();
1815 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001816 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001817 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001818 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001819 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001820 line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001821 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001822 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001823 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001824 }
1825 else
1826 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001827 diagnostics->warning(line, "Divide by zero during constant folding",
1828 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001829 bool negativeResult =
1830 std::signbit(dividend) != std::signbit(divisor);
1831 resultArray[i].setFConst(
1832 negativeResult ? -std::numeric_limits<float>::infinity()
1833 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001834 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001835 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001836 else if (gl::isInf(dividend) && gl::isInf(divisor))
1837 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001838 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001839 "Infinity divided by infinity during constant "
1840 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001841 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001842 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1843 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001844 else
1845 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001846 float result = dividend / divisor;
1847 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001848 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001849 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001850 line, "Constant folded division overflowed to infinity", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001851 }
1852 resultArray[i].setFConst(result);
1853 }
1854 break;
1855 }
1856 case EbtInt:
1857 if (rightArray[i] == 0)
1858 {
1859 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001860 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001861 resultArray[i].setIConst(INT_MAX);
1862 }
1863 else
1864 {
1865 int lhs = leftArray[i].getIConst();
1866 int divisor = rightArray[i].getIConst();
1867 if (op == EOpDiv)
1868 {
1869 // Check for the special case where the minimum representable number
1870 // is
1871 // divided by -1. If left alone this leads to integer overflow in
1872 // C++.
1873 // ESSL 3.00.6 section 4.1.3 Integers:
1874 // "However, for the case where the minimum representable value is
1875 // divided by -1, it is allowed to return either the minimum
1876 // representable value or the maximum representable value."
1877 if (lhs == -0x7fffffff - 1 && divisor == -1)
1878 {
1879 resultArray[i].setIConst(0x7fffffff);
1880 }
1881 else
1882 {
1883 resultArray[i].setIConst(lhs / divisor);
1884 }
Olli Etuahod4453572016-09-27 13:21:46 +01001885 }
1886 else
1887 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001888 ASSERT(op == EOpIMod);
1889 if (lhs < 0 || divisor < 0)
1890 {
1891 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1892 // when
1893 // either one of the operands is negative.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001894 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001895 "Negative modulus operator operand "
1896 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001897 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001898 resultArray[i].setIConst(0);
1899 }
1900 else
1901 {
1902 resultArray[i].setIConst(lhs % divisor);
1903 }
Olli Etuahod4453572016-09-27 13:21:46 +01001904 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001905 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001906 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001907
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001908 case EbtUInt:
1909 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001910 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001911 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001912 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001913 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001914 }
1915 else
1916 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001917 if (op == EOpDiv)
1918 {
1919 resultArray[i].setUConst(leftArray[i].getUConst() /
1920 rightArray[i].getUConst());
1921 }
1922 else
1923 {
1924 ASSERT(op == EOpIMod);
1925 resultArray[i].setUConst(leftArray[i].getUConst() %
1926 rightArray[i].getUConst());
1927 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001928 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001929 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001930
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001931 default:
1932 UNREACHABLE();
1933 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001934 }
1935 }
1936 }
1937 break;
1938
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001939 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001940 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001941 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001942 ASSERT(rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001943
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001944 const int matrixCols = leftType.getCols();
1945 const int matrixRows = leftType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001946
1947 resultArray = new TConstantUnion[matrixRows];
1948
1949 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1950 {
1951 resultArray[matrixRow].setFConst(0.0f);
1952 for (int col = 0; col < matrixCols; col++)
1953 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001954 resultArray[matrixRow].setFConst(
1955 resultArray[matrixRow].getFConst() +
1956 leftArray[col * matrixRows + matrixRow].getFConst() *
1957 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001958 }
1959 }
1960 }
1961 break;
1962
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001963 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001964 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001965 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001966 ASSERT(leftType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001967
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001968 const int matrixCols = rightType.getCols();
1969 const int matrixRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001970
1971 resultArray = new TConstantUnion[matrixCols];
1972
1973 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1974 {
1975 resultArray[matrixCol].setFConst(0.0f);
1976 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1977 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001978 resultArray[matrixCol].setFConst(
1979 resultArray[matrixCol].getFConst() +
1980 leftArray[matrixRow].getFConst() *
1981 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001982 }
1983 }
1984 }
1985 break;
1986
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001987 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001988 {
1989 resultArray = new TConstantUnion[objectSize];
1990 for (size_t i = 0; i < objectSize; i++)
1991 {
1992 resultArray[i] = leftArray[i] && rightArray[i];
1993 }
1994 }
1995 break;
1996
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001997 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001998 {
1999 resultArray = new TConstantUnion[objectSize];
2000 for (size_t i = 0; i < objectSize; i++)
2001 {
2002 resultArray[i] = leftArray[i] || rightArray[i];
2003 }
2004 }
2005 break;
2006
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002007 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002008 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002009 ASSERT(leftType.getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002010 resultArray = new TConstantUnion[objectSize];
2011 for (size_t i = 0; i < objectSize; i++)
2012 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03002013 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002014 }
2015 }
2016 break;
2017
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002018 case EOpBitwiseAnd:
2019 resultArray = new TConstantUnion[objectSize];
2020 for (size_t i = 0; i < objectSize; i++)
2021 resultArray[i] = leftArray[i] & rightArray[i];
2022 break;
2023 case EOpBitwiseXor:
2024 resultArray = new TConstantUnion[objectSize];
2025 for (size_t i = 0; i < objectSize; i++)
2026 resultArray[i] = leftArray[i] ^ rightArray[i];
2027 break;
2028 case EOpBitwiseOr:
2029 resultArray = new TConstantUnion[objectSize];
2030 for (size_t i = 0; i < objectSize; i++)
2031 resultArray[i] = leftArray[i] | rightArray[i];
2032 break;
2033 case EOpBitShiftLeft:
2034 resultArray = new TConstantUnion[objectSize];
2035 for (size_t i = 0; i < objectSize; i++)
2036 resultArray[i] =
2037 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
2038 break;
2039 case EOpBitShiftRight:
2040 resultArray = new TConstantUnion[objectSize];
2041 for (size_t i = 0; i < objectSize; i++)
2042 resultArray[i] =
2043 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
2044 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002045
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002046 case EOpLessThan:
2047 ASSERT(objectSize == 1);
2048 resultArray = new TConstantUnion[1];
2049 resultArray->setBConst(*leftArray < *rightArray);
2050 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002051
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002052 case EOpGreaterThan:
2053 ASSERT(objectSize == 1);
2054 resultArray = new TConstantUnion[1];
2055 resultArray->setBConst(*leftArray > *rightArray);
2056 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002057
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002058 case EOpLessThanEqual:
2059 ASSERT(objectSize == 1);
2060 resultArray = new TConstantUnion[1];
2061 resultArray->setBConst(!(*leftArray > *rightArray));
2062 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002063
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002064 case EOpGreaterThanEqual:
2065 ASSERT(objectSize == 1);
2066 resultArray = new TConstantUnion[1];
2067 resultArray->setBConst(!(*leftArray < *rightArray));
2068 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002069
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002070 case EOpEqual:
2071 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002072 {
2073 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002074 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002075 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002076 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002077 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002078 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002079 equal = false;
2080 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002081 }
2082 }
2083 if (op == EOpEqual)
2084 {
2085 resultArray->setBConst(equal);
2086 }
2087 else
2088 {
2089 resultArray->setBConst(!equal);
2090 }
2091 }
2092 break;
2093
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002094 default:
2095 UNREACHABLE();
2096 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002097 }
2098 return resultArray;
2099}
2100
Olli Etuahof119a262016-08-19 15:54:22 +03002101// The fold functions do operations on a constant at GLSL compile time, without generating run-time
2102// code. Returns the constant value to keep using. Nullptr should not be returned.
2103TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04002104{
Olli Etuahof119a262016-08-19 15:54:22 +03002105 // Do operations where the return type may have a different number of components compared to the
2106 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04002107
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002108 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002109 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302110
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002111 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302112 TConstantUnion *resultArray = nullptr;
2113 switch (op)
2114 {
Olli Etuahof119a262016-08-19 15:54:22 +03002115 case EOpAny:
2116 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302117 resultArray = new TConstantUnion();
2118 resultArray->setBConst(false);
2119 for (size_t i = 0; i < objectSize; i++)
2120 {
2121 if (operandArray[i].getBConst())
2122 {
2123 resultArray->setBConst(true);
2124 break;
2125 }
2126 }
2127 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302128
Olli Etuahof119a262016-08-19 15:54:22 +03002129 case EOpAll:
2130 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302131 resultArray = new TConstantUnion();
2132 resultArray->setBConst(true);
2133 for (size_t i = 0; i < objectSize; i++)
2134 {
2135 if (!operandArray[i].getBConst())
2136 {
2137 resultArray->setBConst(false);
2138 break;
2139 }
2140 }
2141 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302142
Olli Etuahof119a262016-08-19 15:54:22 +03002143 case EOpLength:
2144 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302145 resultArray = new TConstantUnion();
2146 resultArray->setFConst(VectorLength(operandArray, objectSize));
2147 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302148
Olli Etuahof119a262016-08-19 15:54:22 +03002149 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302150 {
Olli Etuahof119a262016-08-19 15:54:22 +03002151 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302152 resultArray = new TConstantUnion[objectSize];
2153 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002154 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302155 SetUnionArrayFromMatrix(result, resultArray);
2156 break;
2157 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302158
Olli Etuahof119a262016-08-19 15:54:22 +03002159 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302160 {
Olli Etuahof119a262016-08-19 15:54:22 +03002161 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302162 unsigned int size = getType().getNominalSize();
2163 ASSERT(size >= 2 && size <= 4);
2164 resultArray = new TConstantUnion();
2165 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
2166 break;
2167 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302168
Olli Etuahof119a262016-08-19 15:54:22 +03002169 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302170 {
Olli Etuahof119a262016-08-19 15:54:22 +03002171 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302172 unsigned int size = getType().getNominalSize();
2173 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03002174 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05302175 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
2176 SetUnionArrayFromMatrix(result, resultArray);
2177 break;
2178 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302179
Olli Etuahof119a262016-08-19 15:54:22 +03002180 case EOpPackSnorm2x16:
2181 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302182 ASSERT(getType().getNominalSize() == 2);
2183 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002184 resultArray->setUConst(
2185 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302186 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302187
Olli Etuahof119a262016-08-19 15:54:22 +03002188 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302189 {
Olli Etuahof119a262016-08-19 15:54:22 +03002190 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302191 resultArray = new TConstantUnion[2];
2192 float f1, f2;
2193 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2194 resultArray[0].setFConst(f1);
2195 resultArray[1].setFConst(f2);
2196 break;
2197 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302198
Olli Etuahof119a262016-08-19 15:54:22 +03002199 case EOpPackUnorm2x16:
2200 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302201 ASSERT(getType().getNominalSize() == 2);
2202 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002203 resultArray->setUConst(
2204 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302205 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302206
Olli Etuahof119a262016-08-19 15:54:22 +03002207 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302208 {
Olli Etuahof119a262016-08-19 15:54:22 +03002209 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302210 resultArray = new TConstantUnion[2];
2211 float f1, f2;
2212 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2213 resultArray[0].setFConst(f1);
2214 resultArray[1].setFConst(f2);
2215 break;
2216 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302217
Olli Etuahof119a262016-08-19 15:54:22 +03002218 case EOpPackHalf2x16:
2219 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302220 ASSERT(getType().getNominalSize() == 2);
2221 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002222 resultArray->setUConst(
2223 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302224 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302225
Olli Etuahof119a262016-08-19 15:54:22 +03002226 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302227 {
Olli Etuahof119a262016-08-19 15:54:22 +03002228 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302229 resultArray = new TConstantUnion[2];
2230 float f1, f2;
2231 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2232 resultArray[0].setFConst(f1);
2233 resultArray[1].setFConst(f2);
2234 break;
2235 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302236
Olli Etuaho25aef452017-01-29 16:15:44 -08002237 case EOpPackUnorm4x8:
2238 {
2239 ASSERT(getType().getBasicType() == EbtFloat);
2240 resultArray = new TConstantUnion();
2241 resultArray->setUConst(
2242 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2243 operandArray[2].getFConst(), operandArray[3].getFConst()));
2244 break;
2245 }
2246 case EOpPackSnorm4x8:
2247 {
2248 ASSERT(getType().getBasicType() == EbtFloat);
2249 resultArray = new TConstantUnion();
2250 resultArray->setUConst(
2251 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2252 operandArray[2].getFConst(), operandArray[3].getFConst()));
2253 break;
2254 }
2255 case EOpUnpackUnorm4x8:
2256 {
2257 ASSERT(getType().getBasicType() == EbtUInt);
2258 resultArray = new TConstantUnion[4];
2259 float f[4];
2260 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2261 for (size_t i = 0; i < 4; ++i)
2262 {
2263 resultArray[i].setFConst(f[i]);
2264 }
2265 break;
2266 }
2267 case EOpUnpackSnorm4x8:
2268 {
2269 ASSERT(getType().getBasicType() == EbtUInt);
2270 resultArray = new TConstantUnion[4];
2271 float f[4];
2272 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2273 for (size_t i = 0; i < 4; ++i)
2274 {
2275 resultArray[i].setFConst(f[i]);
2276 }
2277 break;
2278 }
2279
Olli Etuahof119a262016-08-19 15:54:22 +03002280 default:
2281 UNREACHABLE();
2282 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302283 }
2284
2285 return resultArray;
2286}
2287
Olli Etuahof119a262016-08-19 15:54:22 +03002288TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2289 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302290{
Olli Etuahof119a262016-08-19 15:54:22 +03002291 // Do unary operations where each component of the result is computed based on the corresponding
2292 // component of the operand. Also folds normalize, though the divisor in that case takes all
2293 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302294
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002295 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002296 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002297
2298 size_t objectSize = getType().getObjectSize();
2299
Arun Patoleab2b9a22015-07-06 18:27:56 +05302300 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2301 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302302 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002303 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302304 {
Olli Etuahof119a262016-08-19 15:54:22 +03002305 case EOpNegative:
2306 switch (getType().getBasicType())
2307 {
2308 case EbtFloat:
2309 resultArray[i].setFConst(-operandArray[i].getFConst());
2310 break;
2311 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002312 if (operandArray[i] == std::numeric_limits<int>::min())
2313 {
2314 // The minimum representable integer doesn't have a positive
2315 // counterpart, rather the negation overflows and in ESSL is supposed to
2316 // wrap back to the minimum representable integer. Make sure that we
2317 // don't actually let the negation overflow, which has undefined
2318 // behavior in C++.
2319 resultArray[i].setIConst(std::numeric_limits<int>::min());
2320 }
2321 else
2322 {
2323 resultArray[i].setIConst(-operandArray[i].getIConst());
2324 }
Olli Etuahof119a262016-08-19 15:54:22 +03002325 break;
2326 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002327 if (operandArray[i] == 0x80000000u)
2328 {
2329 resultArray[i].setUConst(0x80000000u);
2330 }
2331 else
2332 {
2333 resultArray[i].setUConst(static_cast<unsigned int>(
2334 -static_cast<int>(operandArray[i].getUConst())));
2335 }
Olli Etuahof119a262016-08-19 15:54:22 +03002336 break;
2337 default:
2338 UNREACHABLE();
2339 return nullptr;
2340 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302341 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302342
Olli Etuahof119a262016-08-19 15:54:22 +03002343 case EOpPositive:
2344 switch (getType().getBasicType())
2345 {
2346 case EbtFloat:
2347 resultArray[i].setFConst(operandArray[i].getFConst());
2348 break;
2349 case EbtInt:
2350 resultArray[i].setIConst(operandArray[i].getIConst());
2351 break;
2352 case EbtUInt:
2353 resultArray[i].setUConst(static_cast<unsigned int>(
2354 static_cast<int>(operandArray[i].getUConst())));
2355 break;
2356 default:
2357 UNREACHABLE();
2358 return nullptr;
2359 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302360 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302361
Olli Etuahof119a262016-08-19 15:54:22 +03002362 case EOpLogicalNot:
2363 switch (getType().getBasicType())
2364 {
2365 case EbtBool:
2366 resultArray[i].setBConst(!operandArray[i].getBConst());
2367 break;
2368 default:
2369 UNREACHABLE();
2370 return nullptr;
2371 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302372 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302373
Olli Etuahof119a262016-08-19 15:54:22 +03002374 case EOpBitwiseNot:
2375 switch (getType().getBasicType())
2376 {
2377 case EbtInt:
2378 resultArray[i].setIConst(~operandArray[i].getIConst());
2379 break;
2380 case EbtUInt:
2381 resultArray[i].setUConst(~operandArray[i].getUConst());
2382 break;
2383 default:
2384 UNREACHABLE();
2385 return nullptr;
2386 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302387 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302388
Olli Etuahof119a262016-08-19 15:54:22 +03002389 case EOpRadians:
2390 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302391 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2392 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302393
Olli Etuahof119a262016-08-19 15:54:22 +03002394 case EOpDegrees:
2395 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302396 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2397 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302398
Olli Etuahof119a262016-08-19 15:54:22 +03002399 case EOpSin:
2400 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302401 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302402
Olli Etuahof119a262016-08-19 15:54:22 +03002403 case EOpCos:
2404 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2405 break;
2406
2407 case EOpTan:
2408 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2409 break;
2410
2411 case EOpAsin:
2412 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2413 // 0.
2414 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2415 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2416 diagnostics, &resultArray[i]);
2417 else
2418 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2419 break;
2420
2421 case EOpAcos:
2422 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2423 // 0.
2424 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2425 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2426 diagnostics, &resultArray[i]);
2427 else
2428 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2429 break;
2430
2431 case EOpAtan:
2432 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2433 break;
2434
2435 case EOpSinh:
2436 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2437 break;
2438
2439 case EOpCosh:
2440 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2441 break;
2442
2443 case EOpTanh:
2444 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2445 break;
2446
2447 case EOpAsinh:
2448 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2449 break;
2450
2451 case EOpAcosh:
2452 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2453 if (operandArray[i].getFConst() < 1.0f)
2454 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2455 diagnostics, &resultArray[i]);
2456 else
2457 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2458 break;
2459
2460 case EOpAtanh:
2461 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2462 // 0.
2463 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2464 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2465 diagnostics, &resultArray[i]);
2466 else
2467 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2468 break;
2469
2470 case EOpAbs:
2471 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302472 {
Olli Etuahof119a262016-08-19 15:54:22 +03002473 case EbtFloat:
2474 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2475 break;
2476 case EbtInt:
2477 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2478 break;
2479 default:
2480 UNREACHABLE();
2481 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302482 }
2483 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002484
2485 case EOpSign:
2486 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302487 {
Olli Etuahof119a262016-08-19 15:54:22 +03002488 case EbtFloat:
2489 {
2490 float fConst = operandArray[i].getFConst();
2491 float fResult = 0.0f;
2492 if (fConst > 0.0f)
2493 fResult = 1.0f;
2494 else if (fConst < 0.0f)
2495 fResult = -1.0f;
2496 resultArray[i].setFConst(fResult);
2497 break;
2498 }
2499 case EbtInt:
2500 {
2501 int iConst = operandArray[i].getIConst();
2502 int iResult = 0;
2503 if (iConst > 0)
2504 iResult = 1;
2505 else if (iConst < 0)
2506 iResult = -1;
2507 resultArray[i].setIConst(iResult);
2508 break;
2509 }
2510 default:
2511 UNREACHABLE();
2512 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302513 }
2514 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302515
Olli Etuahof119a262016-08-19 15:54:22 +03002516 case EOpFloor:
2517 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2518 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302519
Olli Etuahof119a262016-08-19 15:54:22 +03002520 case EOpTrunc:
2521 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2522 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302523
Olli Etuahof119a262016-08-19 15:54:22 +03002524 case EOpRound:
2525 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2526 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302527
Olli Etuahof119a262016-08-19 15:54:22 +03002528 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302529 {
Olli Etuahof119a262016-08-19 15:54:22 +03002530 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302531 float x = operandArray[i].getFConst();
2532 float result;
2533 float fractPart = modff(x, &result);
2534 if (fabsf(fractPart) == 0.5f)
2535 result = 2.0f * roundf(x / 2.0f);
2536 else
2537 result = roundf(x);
2538 resultArray[i].setFConst(result);
2539 break;
2540 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302541
Olli Etuahof119a262016-08-19 15:54:22 +03002542 case EOpCeil:
2543 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2544 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302545
Olli Etuahof119a262016-08-19 15:54:22 +03002546 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302547 {
Olli Etuahof119a262016-08-19 15:54:22 +03002548 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302549 float x = operandArray[i].getFConst();
2550 resultArray[i].setFConst(x - floorf(x));
2551 break;
2552 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302553
Olli Etuahof119a262016-08-19 15:54:22 +03002554 case EOpIsNan:
2555 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302556 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2557 break;
Arun Patole551279e2015-07-07 18:18:23 +05302558
Olli Etuahof119a262016-08-19 15:54:22 +03002559 case EOpIsInf:
2560 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302561 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2562 break;
Arun Patole551279e2015-07-07 18:18:23 +05302563
Olli Etuahof119a262016-08-19 15:54:22 +03002564 case EOpFloatBitsToInt:
2565 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302566 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2567 break;
Arun Patole551279e2015-07-07 18:18:23 +05302568
Olli Etuahof119a262016-08-19 15:54:22 +03002569 case EOpFloatBitsToUint:
2570 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302571 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2572 break;
Arun Patole551279e2015-07-07 18:18:23 +05302573
Olli Etuahof119a262016-08-19 15:54:22 +03002574 case EOpIntBitsToFloat:
2575 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302576 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2577 break;
Arun Patole551279e2015-07-07 18:18:23 +05302578
Olli Etuahof119a262016-08-19 15:54:22 +03002579 case EOpUintBitsToFloat:
2580 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302581 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2582 break;
Arun Patole551279e2015-07-07 18:18:23 +05302583
Olli Etuahof119a262016-08-19 15:54:22 +03002584 case EOpExp:
2585 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2586 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302587
Olli Etuahof119a262016-08-19 15:54:22 +03002588 case EOpLog:
2589 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2590 if (operandArray[i].getFConst() <= 0.0f)
2591 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2592 diagnostics, &resultArray[i]);
2593 else
2594 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2595 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302596
Olli Etuahof119a262016-08-19 15:54:22 +03002597 case EOpExp2:
2598 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2599 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302600
Olli Etuahof119a262016-08-19 15:54:22 +03002601 case EOpLog2:
2602 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2603 // And log2f is not available on some plarforms like old android, so just using
2604 // log(x)/log(2) here.
2605 if (operandArray[i].getFConst() <= 0.0f)
2606 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2607 diagnostics, &resultArray[i]);
2608 else
2609 {
2610 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2611 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2612 }
2613 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302614
Olli Etuahof119a262016-08-19 15:54:22 +03002615 case EOpSqrt:
2616 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2617 if (operandArray[i].getFConst() < 0.0f)
2618 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2619 diagnostics, &resultArray[i]);
2620 else
2621 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2622 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302623
Olli Etuahof119a262016-08-19 15:54:22 +03002624 case EOpInverseSqrt:
2625 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2626 // so getting the square root first using builtin function sqrt() and then taking
2627 // its inverse.
2628 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2629 // result to 0.
2630 if (operandArray[i].getFConst() <= 0.0f)
2631 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2632 diagnostics, &resultArray[i]);
2633 else
2634 {
2635 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2636 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2637 }
2638 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302639
Olli Etuahod68924e2017-01-02 17:34:40 +00002640 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002641 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302642 resultArray[i].setBConst(!operandArray[i].getBConst());
2643 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302644
Olli Etuahof119a262016-08-19 15:54:22 +03002645 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302646 {
Olli Etuahof119a262016-08-19 15:54:22 +03002647 ASSERT(getType().getBasicType() == EbtFloat);
2648 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302649 float length = VectorLength(operandArray, objectSize);
2650 if (length)
2651 resultArray[i].setFConst(x / length);
2652 else
Olli Etuahof119a262016-08-19 15:54:22 +03002653 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2654 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302655 break;
2656 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002657 case EOpBitfieldReverse:
2658 {
2659 uint32_t value;
2660 if (getType().getBasicType() == EbtInt)
2661 {
2662 value = static_cast<uint32_t>(operandArray[i].getIConst());
2663 }
2664 else
2665 {
2666 ASSERT(getType().getBasicType() == EbtUInt);
2667 value = operandArray[i].getUConst();
2668 }
2669 uint32_t result = gl::BitfieldReverse(value);
2670 if (getType().getBasicType() == EbtInt)
2671 {
2672 resultArray[i].setIConst(static_cast<int32_t>(result));
2673 }
2674 else
2675 {
2676 resultArray[i].setUConst(result);
2677 }
2678 break;
2679 }
2680 case EOpBitCount:
2681 {
2682 uint32_t value;
2683 if (getType().getBasicType() == EbtInt)
2684 {
2685 value = static_cast<uint32_t>(operandArray[i].getIConst());
2686 }
2687 else
2688 {
2689 ASSERT(getType().getBasicType() == EbtUInt);
2690 value = operandArray[i].getUConst();
2691 }
2692 int result = gl::BitCount(value);
2693 resultArray[i].setIConst(result);
2694 break;
2695 }
2696 case EOpFindLSB:
2697 {
2698 uint32_t value;
2699 if (getType().getBasicType() == EbtInt)
2700 {
2701 value = static_cast<uint32_t>(operandArray[i].getIConst());
2702 }
2703 else
2704 {
2705 ASSERT(getType().getBasicType() == EbtUInt);
2706 value = operandArray[i].getUConst();
2707 }
2708 resultArray[i].setIConst(gl::FindLSB(value));
2709 break;
2710 }
2711 case EOpFindMSB:
2712 {
2713 uint32_t value;
2714 if (getType().getBasicType() == EbtInt)
2715 {
2716 int intValue = operandArray[i].getIConst();
2717 value = static_cast<uint32_t>(intValue);
2718 if (intValue < 0)
2719 {
2720 // Look for zero instead of one in value. This also handles the intValue ==
2721 // -1 special case, where the return value needs to be -1.
2722 value = ~value;
2723 }
2724 }
2725 else
2726 {
2727 ASSERT(getType().getBasicType() == EbtUInt);
2728 value = operandArray[i].getUConst();
2729 }
2730 resultArray[i].setIConst(gl::FindMSB(value));
2731 break;
2732 }
Olli Etuahof119a262016-08-19 15:54:22 +03002733 case EOpDFdx:
2734 case EOpDFdy:
2735 case EOpFwidth:
2736 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302737 // Derivatives of constant arguments should be 0.
2738 resultArray[i].setFConst(0.0f);
2739 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302740
Olli Etuahof119a262016-08-19 15:54:22 +03002741 default:
2742 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302743 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302744 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002745
Arun Patoleab2b9a22015-07-06 18:27:56 +05302746 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002747}
2748
Olli Etuahof119a262016-08-19 15:54:22 +03002749void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2750 FloatTypeUnaryFunc builtinFunc,
2751 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302752{
2753 ASSERT(builtinFunc);
2754
Olli Etuahof119a262016-08-19 15:54:22 +03002755 ASSERT(getType().getBasicType() == EbtFloat);
2756 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302757}
2758
Jamie Madillb1a85f42014-08-19 15:23:24 -04002759// static
Olli Etuahof119a262016-08-19 15:54:22 +03002760TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2761 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302762{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002763 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002764 TIntermSequence *arguments = aggregate->getSequence();
2765 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2766 std::vector<const TConstantUnion *> unionArrays(argsCount);
2767 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002768 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302769 TBasicType basicType = EbtVoid;
2770 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002771 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302772 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002773 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2774 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302775
2776 if (i == 0)
2777 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002778 basicType = argConstant->getType().getBasicType();
2779 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302780 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002781 unionArrays[i] = argConstant->getConstantValue();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002782 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002783 if (objectSizes[i] > maxObjectSize)
2784 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302785 }
2786
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002787 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302788 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002789 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302790 if (objectSizes[i] != maxObjectSize)
2791 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2792 }
Arun Patole274f0702015-05-05 13:33:30 +05302793
Olli Etuahob43846e2015-06-02 18:18:57 +03002794 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002795
2796 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302797 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002798 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302799 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002800 ASSERT(basicType == EbtFloat);
2801 resultArray = new TConstantUnion[maxObjectSize];
2802 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302803 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002804 float y = unionArrays[0][i].getFConst();
2805 float x = unionArrays[1][i].getFConst();
2806 // Results are undefined if x and y are both 0.
2807 if (x == 0.0f && y == 0.0f)
2808 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2809 else
2810 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302811 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002812 break;
2813 }
Arun Patolebf790422015-05-18 17:53:04 +05302814
Olli Etuaho51182ab2017-01-22 00:12:29 +00002815 case EOpPow:
2816 {
2817 ASSERT(basicType == EbtFloat);
2818 resultArray = new TConstantUnion[maxObjectSize];
2819 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302820 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002821 float x = unionArrays[0][i].getFConst();
2822 float y = unionArrays[1][i].getFConst();
2823 // Results are undefined if x < 0.
2824 // Results are undefined if x = 0 and y <= 0.
2825 if (x < 0.0f)
2826 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2827 else if (x == 0.0f && y <= 0.0f)
2828 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2829 else
2830 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302831 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002832 break;
2833 }
Arun Patolebf790422015-05-18 17:53:04 +05302834
Olli Etuaho51182ab2017-01-22 00:12:29 +00002835 case EOpMod:
2836 {
2837 ASSERT(basicType == EbtFloat);
2838 resultArray = new TConstantUnion[maxObjectSize];
2839 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302840 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002841 float x = unionArrays[0][i].getFConst();
2842 float y = unionArrays[1][i].getFConst();
2843 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302844 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002845 break;
2846 }
Arun Patolebf790422015-05-18 17:53:04 +05302847
Olli Etuaho51182ab2017-01-22 00:12:29 +00002848 case EOpMin:
2849 {
2850 resultArray = new TConstantUnion[maxObjectSize];
2851 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302852 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002853 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302854 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002855 case EbtFloat:
2856 resultArray[i].setFConst(
2857 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2858 break;
2859 case EbtInt:
2860 resultArray[i].setIConst(
2861 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2862 break;
2863 case EbtUInt:
2864 resultArray[i].setUConst(
2865 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2866 break;
2867 default:
2868 UNREACHABLE();
2869 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302870 }
2871 }
2872 break;
Arun Patole274f0702015-05-05 13:33:30 +05302873 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002874
2875 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302876 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002877 resultArray = new TConstantUnion[maxObjectSize];
2878 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302879 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002880 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302881 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002882 case EbtFloat:
2883 resultArray[i].setFConst(
2884 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2885 break;
2886 case EbtInt:
2887 resultArray[i].setIConst(
2888 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2889 break;
2890 case EbtUInt:
2891 resultArray[i].setUConst(
2892 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2893 break;
2894 default:
2895 UNREACHABLE();
2896 break;
Arun Patole274f0702015-05-05 13:33:30 +05302897 }
2898 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002899 break;
Arun Patole274f0702015-05-05 13:33:30 +05302900 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002901
2902 case EOpStep:
2903 {
2904 ASSERT(basicType == EbtFloat);
2905 resultArray = new TConstantUnion[maxObjectSize];
2906 for (size_t i = 0; i < maxObjectSize; i++)
2907 resultArray[i].setFConst(
2908 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2909 break;
2910 }
2911
2912 case EOpLessThanComponentWise:
2913 {
2914 resultArray = new TConstantUnion[maxObjectSize];
2915 for (size_t i = 0; i < maxObjectSize; i++)
2916 {
2917 switch (basicType)
2918 {
2919 case EbtFloat:
2920 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2921 unionArrays[1][i].getFConst());
2922 break;
2923 case EbtInt:
2924 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2925 unionArrays[1][i].getIConst());
2926 break;
2927 case EbtUInt:
2928 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2929 unionArrays[1][i].getUConst());
2930 break;
2931 default:
2932 UNREACHABLE();
2933 break;
2934 }
2935 }
2936 break;
2937 }
2938
2939 case EOpLessThanEqualComponentWise:
2940 {
2941 resultArray = new TConstantUnion[maxObjectSize];
2942 for (size_t i = 0; i < maxObjectSize; i++)
2943 {
2944 switch (basicType)
2945 {
2946 case EbtFloat:
2947 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2948 unionArrays[1][i].getFConst());
2949 break;
2950 case EbtInt:
2951 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2952 unionArrays[1][i].getIConst());
2953 break;
2954 case EbtUInt:
2955 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2956 unionArrays[1][i].getUConst());
2957 break;
2958 default:
2959 UNREACHABLE();
2960 break;
2961 }
2962 }
2963 break;
2964 }
2965
2966 case EOpGreaterThanComponentWise:
2967 {
2968 resultArray = new TConstantUnion[maxObjectSize];
2969 for (size_t i = 0; i < maxObjectSize; i++)
2970 {
2971 switch (basicType)
2972 {
2973 case EbtFloat:
2974 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2975 unionArrays[1][i].getFConst());
2976 break;
2977 case EbtInt:
2978 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2979 unionArrays[1][i].getIConst());
2980 break;
2981 case EbtUInt:
2982 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2983 unionArrays[1][i].getUConst());
2984 break;
2985 default:
2986 UNREACHABLE();
2987 break;
2988 }
2989 }
2990 break;
2991 }
2992 case EOpGreaterThanEqualComponentWise:
2993 {
2994 resultArray = new TConstantUnion[maxObjectSize];
2995 for (size_t i = 0; i < maxObjectSize; i++)
2996 {
2997 switch (basicType)
2998 {
2999 case EbtFloat:
3000 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
3001 unionArrays[1][i].getFConst());
3002 break;
3003 case EbtInt:
3004 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
3005 unionArrays[1][i].getIConst());
3006 break;
3007 case EbtUInt:
3008 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
3009 unionArrays[1][i].getUConst());
3010 break;
3011 default:
3012 UNREACHABLE();
3013 break;
3014 }
3015 }
3016 }
3017 break;
3018
3019 case EOpEqualComponentWise:
3020 {
3021 resultArray = new TConstantUnion[maxObjectSize];
3022 for (size_t i = 0; i < maxObjectSize; i++)
3023 {
3024 switch (basicType)
3025 {
3026 case EbtFloat:
3027 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
3028 unionArrays[1][i].getFConst());
3029 break;
3030 case EbtInt:
3031 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
3032 unionArrays[1][i].getIConst());
3033 break;
3034 case EbtUInt:
3035 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
3036 unionArrays[1][i].getUConst());
3037 break;
3038 case EbtBool:
3039 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
3040 unionArrays[1][i].getBConst());
3041 break;
3042 default:
3043 UNREACHABLE();
3044 break;
3045 }
3046 }
3047 break;
3048 }
3049
3050 case EOpNotEqualComponentWise:
3051 {
3052 resultArray = new TConstantUnion[maxObjectSize];
3053 for (size_t i = 0; i < maxObjectSize; i++)
3054 {
3055 switch (basicType)
3056 {
3057 case EbtFloat:
3058 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
3059 unionArrays[1][i].getFConst());
3060 break;
3061 case EbtInt:
3062 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3063 unionArrays[1][i].getIConst());
3064 break;
3065 case EbtUInt:
3066 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3067 unionArrays[1][i].getUConst());
3068 break;
3069 case EbtBool:
3070 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3071 unionArrays[1][i].getBConst());
3072 break;
3073 default:
3074 UNREACHABLE();
3075 break;
3076 }
3077 }
3078 break;
3079 }
3080
3081 case EOpDistance:
3082 {
3083 ASSERT(basicType == EbtFloat);
3084 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3085 resultArray = new TConstantUnion();
3086 for (size_t i = 0; i < maxObjectSize; i++)
3087 {
3088 float x = unionArrays[0][i].getFConst();
3089 float y = unionArrays[1][i].getFConst();
3090 distanceArray[i].setFConst(x - y);
3091 }
3092 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3093 break;
3094 }
3095
3096 case EOpDot:
3097 ASSERT(basicType == EbtFloat);
3098 resultArray = new TConstantUnion();
3099 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3100 break;
3101
3102 case EOpCross:
3103 {
3104 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3105 resultArray = new TConstantUnion[maxObjectSize];
3106 float x0 = unionArrays[0][0].getFConst();
3107 float x1 = unionArrays[0][1].getFConst();
3108 float x2 = unionArrays[0][2].getFConst();
3109 float y0 = unionArrays[1][0].getFConst();
3110 float y1 = unionArrays[1][1].getFConst();
3111 float y2 = unionArrays[1][2].getFConst();
3112 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3113 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3114 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3115 break;
3116 }
3117
3118 case EOpReflect:
3119 {
3120 ASSERT(basicType == EbtFloat);
3121 // genType reflect (genType I, genType N) :
3122 // For the incident vector I and surface orientation N, returns the reflection
3123 // direction:
3124 // I - 2 * dot(N, I) * N.
3125 resultArray = new TConstantUnion[maxObjectSize];
3126 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3127 for (size_t i = 0; i < maxObjectSize; i++)
3128 {
3129 float result = unionArrays[0][i].getFConst() -
3130 2.0f * dotProduct * unionArrays[1][i].getFConst();
3131 resultArray[i].setFConst(result);
3132 }
3133 break;
3134 }
3135
3136 case EOpMulMatrixComponentWise:
3137 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003138 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3139 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003140 // Perform component-wise matrix multiplication.
3141 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003142 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003143 angle::Matrix<float> result =
3144 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3145 SetUnionArrayFromMatrix(result, resultArray);
3146 break;
3147 }
3148
3149 case EOpOuterProduct:
3150 {
3151 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003152 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3153 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003154 resultArray = new TConstantUnion[numRows * numCols];
3155 angle::Matrix<float> result =
3156 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3157 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3158 SetUnionArrayFromMatrix(result, resultArray);
3159 break;
3160 }
3161
3162 case EOpClamp:
3163 {
3164 resultArray = new TConstantUnion[maxObjectSize];
3165 for (size_t i = 0; i < maxObjectSize; i++)
3166 {
3167 switch (basicType)
3168 {
3169 case EbtFloat:
3170 {
3171 float x = unionArrays[0][i].getFConst();
3172 float min = unionArrays[1][i].getFConst();
3173 float max = unionArrays[2][i].getFConst();
3174 // Results are undefined if min > max.
3175 if (min > max)
3176 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3177 &resultArray[i]);
3178 else
3179 resultArray[i].setFConst(gl::clamp(x, min, max));
3180 break;
3181 }
3182
3183 case EbtInt:
3184 {
3185 int x = unionArrays[0][i].getIConst();
3186 int min = unionArrays[1][i].getIConst();
3187 int max = unionArrays[2][i].getIConst();
3188 // Results are undefined if min > max.
3189 if (min > max)
3190 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3191 &resultArray[i]);
3192 else
3193 resultArray[i].setIConst(gl::clamp(x, min, max));
3194 break;
3195 }
3196 case EbtUInt:
3197 {
3198 unsigned int x = unionArrays[0][i].getUConst();
3199 unsigned int min = unionArrays[1][i].getUConst();
3200 unsigned int max = unionArrays[2][i].getUConst();
3201 // Results are undefined if min > max.
3202 if (min > max)
3203 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3204 &resultArray[i]);
3205 else
3206 resultArray[i].setUConst(gl::clamp(x, min, max));
3207 break;
3208 }
3209 default:
3210 UNREACHABLE();
3211 break;
3212 }
3213 }
3214 break;
3215 }
3216
3217 case EOpMix:
3218 {
3219 ASSERT(basicType == EbtFloat);
3220 resultArray = new TConstantUnion[maxObjectSize];
3221 for (size_t i = 0; i < maxObjectSize; i++)
3222 {
3223 float x = unionArrays[0][i].getFConst();
3224 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003225 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003226 if (type == EbtFloat)
3227 {
3228 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3229 float a = unionArrays[2][i].getFConst();
3230 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3231 }
3232 else // 3rd parameter is EbtBool
3233 {
3234 ASSERT(type == EbtBool);
3235 // Selects which vector each returned component comes from.
3236 // For a component of a that is false, the corresponding component of x is
3237 // returned.
3238 // For a component of a that is true, the corresponding component of y is
3239 // returned.
3240 bool a = unionArrays[2][i].getBConst();
3241 resultArray[i].setFConst(a ? y : x);
3242 }
3243 }
3244 break;
3245 }
3246
3247 case EOpSmoothStep:
3248 {
3249 ASSERT(basicType == EbtFloat);
3250 resultArray = new TConstantUnion[maxObjectSize];
3251 for (size_t i = 0; i < maxObjectSize; i++)
3252 {
3253 float edge0 = unionArrays[0][i].getFConst();
3254 float edge1 = unionArrays[1][i].getFConst();
3255 float x = unionArrays[2][i].getFConst();
3256 // Results are undefined if edge0 >= edge1.
3257 if (edge0 >= edge1)
3258 {
3259 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3260 }
3261 else
3262 {
3263 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3264 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3265 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3266 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3267 }
3268 }
3269 break;
3270 }
3271
Olli Etuaho74da73f2017-02-01 15:37:48 +00003272 case EOpLdexp:
3273 {
3274 resultArray = new TConstantUnion[maxObjectSize];
3275 for (size_t i = 0; i < maxObjectSize; i++)
3276 {
3277 float x = unionArrays[0][i].getFConst();
3278 int exp = unionArrays[1][i].getIConst();
3279 if (exp > 128)
3280 {
3281 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3282 }
3283 else
3284 {
3285 resultArray[i].setFConst(gl::Ldexp(x, exp));
3286 }
3287 }
3288 break;
3289 }
3290
Jamie Madille72595b2017-06-06 15:12:26 -04003291 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003292 {
3293 ASSERT(basicType == EbtFloat);
3294 // genType faceforward(genType N, genType I, genType Nref) :
3295 // If dot(Nref, I) < 0 return N, otherwise return -N.
3296 resultArray = new TConstantUnion[maxObjectSize];
3297 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3298 for (size_t i = 0; i < maxObjectSize; i++)
3299 {
3300 if (dotProduct < 0)
3301 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3302 else
3303 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3304 }
3305 break;
3306 }
3307
3308 case EOpRefract:
3309 {
3310 ASSERT(basicType == EbtFloat);
3311 // genType refract(genType I, genType N, float eta) :
3312 // For the incident vector I and surface normal N, and the ratio of indices of
3313 // refraction eta,
3314 // return the refraction vector. The result is computed by
3315 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3316 // if (k < 0.0)
3317 // return genType(0.0)
3318 // else
3319 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3320 resultArray = new TConstantUnion[maxObjectSize];
3321 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3322 for (size_t i = 0; i < maxObjectSize; i++)
3323 {
3324 float eta = unionArrays[2][i].getFConst();
3325 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3326 if (k < 0.0f)
3327 resultArray[i].setFConst(0.0f);
3328 else
3329 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3330 (eta * dotProduct + sqrtf(k)) *
3331 unionArrays[1][i].getFConst());
3332 }
3333 break;
3334 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003335 case EOpBitfieldExtract:
3336 {
3337 resultArray = new TConstantUnion[maxObjectSize];
3338 for (size_t i = 0; i < maxObjectSize; ++i)
3339 {
3340 int offset = unionArrays[1][0].getIConst();
3341 int bits = unionArrays[2][0].getIConst();
3342 if (bits == 0)
3343 {
3344 if (aggregate->getBasicType() == EbtInt)
3345 {
3346 resultArray[i].setIConst(0);
3347 }
3348 else
3349 {
3350 ASSERT(aggregate->getBasicType() == EbtUInt);
3351 resultArray[i].setUConst(0);
3352 }
3353 }
3354 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3355 {
3356 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3357 &resultArray[i]);
3358 }
3359 else
3360 {
3361 // bits can be 32 here, so we need to avoid bit shift overflow.
3362 uint32_t maskMsb = 1u << (bits - 1);
3363 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3364 if (aggregate->getBasicType() == EbtInt)
3365 {
3366 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3367 uint32_t resultUnsigned = (value & mask) >> offset;
3368 if ((resultUnsigned & maskMsb) != 0)
3369 {
3370 // The most significant bits (from bits+1 to the most significant bit)
3371 // should be set to 1.
3372 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3373 resultUnsigned |= higherBitsMask;
3374 }
3375 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3376 }
3377 else
3378 {
3379 ASSERT(aggregate->getBasicType() == EbtUInt);
3380 uint32_t value = unionArrays[0][i].getUConst();
3381 resultArray[i].setUConst((value & mask) >> offset);
3382 }
3383 }
3384 }
3385 break;
3386 }
3387 case EOpBitfieldInsert:
3388 {
3389 resultArray = new TConstantUnion[maxObjectSize];
3390 for (size_t i = 0; i < maxObjectSize; ++i)
3391 {
3392 int offset = unionArrays[2][0].getIConst();
3393 int bits = unionArrays[3][0].getIConst();
3394 if (bits == 0)
3395 {
3396 if (aggregate->getBasicType() == EbtInt)
3397 {
3398 int32_t base = unionArrays[0][i].getIConst();
3399 resultArray[i].setIConst(base);
3400 }
3401 else
3402 {
3403 ASSERT(aggregate->getBasicType() == EbtUInt);
3404 uint32_t base = unionArrays[0][i].getUConst();
3405 resultArray[i].setUConst(base);
3406 }
3407 }
3408 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3409 {
3410 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3411 &resultArray[i]);
3412 }
3413 else
3414 {
3415 // bits can be 32 here, so we need to avoid bit shift overflow.
3416 uint32_t maskMsb = 1u << (bits - 1);
3417 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3418 uint32_t baseMask = ~insertMask;
3419 if (aggregate->getBasicType() == EbtInt)
3420 {
3421 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3422 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3423 uint32_t resultUnsigned =
3424 (base & baseMask) | ((insert << offset) & insertMask);
3425 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3426 }
3427 else
3428 {
3429 ASSERT(aggregate->getBasicType() == EbtUInt);
3430 uint32_t base = unionArrays[0][i].getUConst();
3431 uint32_t insert = unionArrays[1][i].getUConst();
3432 resultArray[i].setUConst((base & baseMask) |
3433 ((insert << offset) & insertMask));
3434 }
3435 }
3436 }
3437 break;
3438 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003439
3440 default:
3441 UNREACHABLE();
3442 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303443 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003444 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303445}
3446
Jamie Madill45bcc782016-11-07 13:58:48 -05003447} // namespace sh