blob: 965327c07f368aeeaad31fb04da5be9e9f4b0124 [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
Olli Etuaho68981eb2018-01-23 17:46:12 +0200367TIntermAggregate *TIntermAggregate::Create(const TFunction &func,
Olli Etuahofe486322017-03-21 09:30:54 +0000368 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
Olli Etuaho68981eb2018-01-23 17:46:12 +0200375 return new TIntermAggregate(&func, func.getReturnType(), 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 Etuaho0c371002017-12-13 17:00:25 +0400512const char *TIntermAggregate::functionName() 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 mFunction->name().c_str();
Olli Etuaho0c371002017-12-13 17:00:25 +0400521 default:
522 return GetOperatorString(mOp);
523 }
524}
525
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200526bool TIntermAggregate::hasConstantValue() const
527{
528 if (!isConstructor())
529 {
530 return false;
531 }
532 for (TIntermNode *constructorArg : mArguments)
533 {
534 if (!constructorArg->getAsTyped()->hasConstantValue())
535 {
536 return false;
537 }
538 }
539 return true;
540}
541
542const TConstantUnion *TIntermAggregate::getConstantValue() const
543{
544 if (!hasConstantValue())
545 {
546 return nullptr;
547 }
548 ASSERT(isConstructor());
549 ASSERT(mArguments.size() > 0u);
550
551 TConstantUnion *constArray = nullptr;
552 if (isArray())
553 {
554 size_t elementSize = mArguments.front()->getAsTyped()->getType().getObjectSize();
555 constArray = new TConstantUnion[elementSize * getOutermostArraySize()];
556
557 size_t elementOffset = 0u;
558 for (TIntermNode *constructorArg : mArguments)
559 {
560 const TConstantUnion *elementConstArray =
561 constructorArg->getAsTyped()->getConstantValue();
562 ASSERT(elementConstArray);
563 size_t elementSizeBytes = sizeof(TConstantUnion) * elementSize;
564 memcpy(static_cast<void *>(&constArray[elementOffset]),
565 static_cast<const void *>(elementConstArray), elementSizeBytes);
566 elementOffset += elementSize;
567 }
568 return constArray;
569 }
570
571 size_t resultSize = getType().getObjectSize();
572 constArray = new TConstantUnion[resultSize];
573 TBasicType basicType = getBasicType();
574
575 size_t resultIndex = 0u;
576
577 if (mArguments.size() == 1u)
578 {
579 TIntermNode *argument = mArguments.front();
580 TIntermTyped *argumentTyped = argument->getAsTyped();
581 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
582 // Check the special case of constructing a matrix diagonal from a single scalar,
583 // or a vector from a single scalar.
584 if (argumentTyped->getType().getObjectSize() == 1u)
585 {
586 if (isMatrix())
587 {
588 int resultCols = getType().getCols();
589 int resultRows = getType().getRows();
590 for (int col = 0; col < resultCols; ++col)
591 {
592 for (int row = 0; row < resultRows; ++row)
593 {
594 if (col == row)
595 {
596 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
597 }
598 else
599 {
600 constArray[resultIndex].setFConst(0.0f);
601 }
602 ++resultIndex;
603 }
604 }
605 }
606 else
607 {
608 while (resultIndex < resultSize)
609 {
610 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
611 ++resultIndex;
612 }
613 }
614 ASSERT(resultIndex == resultSize);
615 return constArray;
616 }
617 else if (isMatrix() && argumentTyped->isMatrix())
618 {
619 // The special case of constructing a matrix from a matrix.
620 int argumentCols = argumentTyped->getType().getCols();
621 int argumentRows = argumentTyped->getType().getRows();
622 int resultCols = getType().getCols();
623 int resultRows = getType().getRows();
624 for (int col = 0; col < resultCols; ++col)
625 {
626 for (int row = 0; row < resultRows; ++row)
627 {
628 if (col < argumentCols && row < argumentRows)
629 {
630 constArray[resultIndex].cast(
631 basicType, argumentConstantValue[col * argumentRows + row]);
632 }
633 else if (col == row)
634 {
635 constArray[resultIndex].setFConst(1.0f);
636 }
637 else
638 {
639 constArray[resultIndex].setFConst(0.0f);
640 }
641 ++resultIndex;
642 }
643 }
644 ASSERT(resultIndex == resultSize);
645 return constArray;
646 }
647 }
648
649 for (TIntermNode *argument : mArguments)
650 {
651 TIntermTyped *argumentTyped = argument->getAsTyped();
652 size_t argumentSize = argumentTyped->getType().getObjectSize();
653 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
654 for (size_t i = 0u; i < argumentSize; ++i)
655 {
656 if (resultIndex >= resultSize)
657 break;
658 constArray[resultIndex].cast(basicType, argumentConstantValue[i]);
659 ++resultIndex;
660 }
661 }
662 ASSERT(resultIndex == resultSize);
663 return constArray;
664}
665
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300666bool TIntermAggregate::hasSideEffects() const
667{
Olli Etuahoea78d2b2018-01-09 12:55:27 +0200668 if (getQualifier() == EvqConst)
669 {
670 return false;
671 }
672 bool calledFunctionHasNoSideEffects =
673 isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects();
674 if (calledFunctionHasNoSideEffects || isConstructor())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300675 {
676 for (TIntermNode *arg : mArguments)
677 {
678 if (arg->getAsTyped()->hasSideEffects())
679 {
680 return true;
681 }
682 }
683 return false;
684 }
685 // Conservatively assume most aggregate operators have side-effects
686 return true;
687}
688
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100689void TIntermBlock::appendStatement(TIntermNode *statement)
690{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300691 // Declaration nodes with no children can appear if it was an empty declaration or if all the
692 // declarators just added constants to the symbol table instead of generating code. We still
693 // need to add the declaration to the AST in that case because it might be relevant to the
694 // validity of switch/case.
695 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100696 {
697 mStatements.push_back(statement);
698 }
699}
700
Olli Etuaho16c745a2017-01-16 17:02:27 +0000701void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
702{
703 ASSERT(parameter != nullptr);
704 mParameters.push_back(parameter);
705}
706
Olli Etuaho13389b62016-10-16 11:48:18 +0100707void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
708{
709 ASSERT(declarator != nullptr);
710 ASSERT(declarator->getAsSymbolNode() != nullptr ||
711 (declarator->getAsBinaryNode() != nullptr &&
712 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
713 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300714 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100715 mDeclarators.push_back(declarator);
716}
717
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300718bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
719{
720 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
721 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
722 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
723 return false;
724}
725
Olli Etuaho57961272016-09-14 13:57:46 +0300726bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400727{
728 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100729 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
730 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400731 return false;
732}
733
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500734bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200735{
736 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100737 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300738 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200739 return false;
740}
741
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500742bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200743{
744 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
745 return false;
746}
747
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200748TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode()
Olli Etuahod7a25242015-08-18 13:49:45 +0300749{
750 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
751 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200752 // We need to manually copy any fields of TIntermNode.
Olli Etuahod7a25242015-08-18 13:49:45 +0300753 mLine = node.mLine;
754}
755
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200756bool TIntermTyped::hasConstantValue() const
Olli Etuahod4f4c112016-04-15 15:11:24 +0300757{
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200758 return false;
759}
760
761const TConstantUnion *TIntermTyped::getConstantValue() const
762{
763 return nullptr;
Olli Etuahod4f4c112016-04-15 15:11:24 +0300764}
765
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200766TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node)
767 : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300768{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200769 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300770}
771
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200772TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200773 : TIntermTyped(), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100774{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200775 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100776}
777
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200778const TType &TIntermFunctionPrototype::getType() const
779{
780 return mFunction->getReturnType();
781}
782
Olli Etuahod7a25242015-08-18 13:49:45 +0300783TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
784 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300785 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100786 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400787 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300788{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800789 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300790 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800791 TIntermTyped *typedArg = arg->getAsTyped();
792 ASSERT(typedArg != nullptr);
793 TIntermTyped *argCopy = typedArg->deepCopy();
794 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300795 }
796}
797
Olli Etuahofe486322017-03-21 09:30:54 +0000798TIntermAggregate *TIntermAggregate::shallowCopy() const
799{
800 TIntermSequence *copySeq = new TIntermSequence();
801 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400802 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000803 copyNode->setLine(mLine);
804 return copyNode;
805}
806
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200807TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermExpression(node)
Olli Etuahob6fa0432016-09-28 16:28:05 +0100808{
809 TIntermTyped *operandCopy = node.mOperand->deepCopy();
810 ASSERT(operandCopy != nullptr);
811 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000812 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100813}
814
Olli Etuahod7a25242015-08-18 13:49:45 +0300815TIntermBinary::TIntermBinary(const TIntermBinary &node)
816 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
817{
818 TIntermTyped *leftCopy = node.mLeft->deepCopy();
819 TIntermTyped *rightCopy = node.mRight->deepCopy();
820 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
821 mLeft = leftCopy;
822 mRight = rightCopy;
823}
824
825TIntermUnary::TIntermUnary(const TIntermUnary &node)
826 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
827{
828 TIntermTyped *operandCopy = node.mOperand->deepCopy();
829 ASSERT(operandCopy != nullptr);
830 mOperand = operandCopy;
831}
832
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200833TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300834{
Olli Etuahod7a25242015-08-18 13:49:45 +0300835 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300836 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
837 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300838 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300839 mCondition = conditionCopy;
840 mTrueExpression = trueCopy;
841 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300842}
843
Jamie Madillb1a85f42014-08-19 15:23:24 -0400844bool TIntermOperator::isAssignment() const
845{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300846 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400847}
848
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300849bool TIntermOperator::isMultiplication() const
850{
851 switch (mOp)
852 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500853 case EOpMul:
854 case EOpMatrixTimesMatrix:
855 case EOpMatrixTimesVector:
856 case EOpMatrixTimesScalar:
857 case EOpVectorTimesMatrix:
858 case EOpVectorTimesScalar:
859 return true;
860 default:
861 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300862 }
863}
864
Jamie Madillb1a85f42014-08-19 15:23:24 -0400865bool TIntermOperator::isConstructor() const
866{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300867 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400868}
869
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800870bool TIntermOperator::isFunctionCall() const
871{
872 switch (mOp)
873 {
874 case EOpCallFunctionInAST:
875 case EOpCallBuiltInFunction:
876 case EOpCallInternalRawFunction:
877 return true;
878 default:
879 return false;
880 }
881}
882
Olli Etuaho1dded802016-08-18 18:13:13 +0300883TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
884{
885 if (left.isMatrix())
886 {
887 if (right.isMatrix())
888 {
889 return EOpMatrixTimesMatrix;
890 }
891 else
892 {
893 if (right.isVector())
894 {
895 return EOpMatrixTimesVector;
896 }
897 else
898 {
899 return EOpMatrixTimesScalar;
900 }
901 }
902 }
903 else
904 {
905 if (right.isMatrix())
906 {
907 if (left.isVector())
908 {
909 return EOpVectorTimesMatrix;
910 }
911 else
912 {
913 return EOpMatrixTimesScalar;
914 }
915 }
916 else
917 {
918 // Neither operand is a matrix.
919 if (left.isVector() == right.isVector())
920 {
921 // Leave as component product.
922 return EOpMul;
923 }
924 else
925 {
926 return EOpVectorTimesScalar;
927 }
928 }
929 }
930}
931
932TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
933{
934 if (left.isMatrix())
935 {
936 if (right.isMatrix())
937 {
938 return EOpMatrixTimesMatrixAssign;
939 }
940 else
941 {
942 // right should be scalar, but this may not be validated yet.
943 return EOpMatrixTimesScalarAssign;
944 }
945 }
946 else
947 {
948 if (right.isMatrix())
949 {
950 // Left should be a vector, but this may not be validated yet.
951 return EOpVectorTimesMatrixAssign;
952 }
953 else
954 {
955 // Neither operand is a matrix.
956 if (left.isVector() == right.isVector())
957 {
958 // Leave as component product.
959 return EOpMulAssign;
960 }
961 else
962 {
963 // left should be vector and right should be scalar, but this may not be validated
964 // yet.
965 return EOpVectorTimesScalarAssign;
966 }
967 }
968 }
969}
970
Jamie Madillb1a85f42014-08-19 15:23:24 -0400971//
972// Make sure the type of a unary operator is appropriate for its
973// combination of operation and operand type.
974//
Olli Etuahoa2234302016-08-31 12:05:39 +0300975void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400976{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300977 if (mOp == EOpArrayLength)
978 {
979 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
980 setType(TType(EbtInt, EbpUndefined, EvqConst));
981 return;
982 }
983
Olli Etuahoa2234302016-08-31 12:05:39 +0300984 TQualifier resultQualifier = EvqTemporary;
985 if (mOperand->getQualifier() == EvqConst)
986 resultQualifier = EvqConst;
987
988 unsigned char operandPrimarySize =
989 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400990 switch (mOp)
991 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300992 case EOpFloatBitsToInt:
993 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
994 break;
995 case EOpFloatBitsToUint:
996 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
997 break;
998 case EOpIntBitsToFloat:
999 case EOpUintBitsToFloat:
1000 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
1001 break;
1002 case EOpPackSnorm2x16:
1003 case EOpPackUnorm2x16:
1004 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001005 case EOpPackUnorm4x8:
1006 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +03001007 setType(TType(EbtUInt, EbpHigh, resultQualifier));
1008 break;
1009 case EOpUnpackSnorm2x16:
1010 case EOpUnpackUnorm2x16:
1011 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
1012 break;
1013 case EOpUnpackHalf2x16:
1014 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
1015 break;
Olli Etuaho25aef452017-01-29 16:15:44 -08001016 case EOpUnpackUnorm4x8:
1017 case EOpUnpackSnorm4x8:
1018 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
1019 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001020 case EOpAny:
1021 case EOpAll:
1022 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1023 break;
1024 case EOpLength:
1025 case EOpDeterminant:
1026 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
1027 break;
1028 case EOpTranspose:
1029 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
1030 static_cast<unsigned char>(mOperand->getType().getRows()),
1031 static_cast<unsigned char>(mOperand->getType().getCols())));
1032 break;
1033 case EOpIsInf:
1034 case EOpIsNan:
1035 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
1036 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001037 case EOpBitfieldReverse:
1038 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
1039 break;
1040 case EOpBitCount:
1041 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1042 break;
1043 case EOpFindLSB:
1044 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1045 break;
1046 case EOpFindMSB:
1047 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1048 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001049 default:
1050 setType(mOperand->getType());
1051 mType.setQualifier(resultQualifier);
1052 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001053 }
Olli Etuahoa2234302016-08-31 12:05:39 +03001054}
Jamie Madillb1a85f42014-08-19 15:23:24 -04001055
Olli Etuahob6fa0432016-09-28 16:28:05 +01001056TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001057 : TIntermExpression(TType(EbtFloat, EbpUndefined)),
Olli Etuahob6fa0432016-09-28 16:28:05 +01001058 mOperand(operand),
1059 mSwizzleOffsets(swizzleOffsets)
1060{
1061 ASSERT(mSwizzleOffsets.size() <= 4);
1062 promote();
1063}
1064
Olli Etuahoa2234302016-08-31 12:05:39 +03001065TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
1066 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
1067{
1068 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001069}
1070
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001071TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1072 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
1073{
1074 promote();
1075}
1076
Olli Etuaho0e99b7a2018-01-12 12:05:48 +02001077TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left,
1078 TIntermTyped *right,
1079 int shaderVersion)
1080{
1081 TIntermBinary *node = new TIntermBinary(EOpComma, left, right);
1082 node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right));
1083 return node;
1084}
1085
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001086TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1087 : TIntermNode(), mSymbol(symbol)
1088{
1089 ASSERT(symbol);
1090 setLine(line);
1091}
1092
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001093TIntermTernary::TIntermTernary(TIntermTyped *cond,
1094 TIntermTyped *trueExpression,
1095 TIntermTyped *falseExpression)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001096 : TIntermExpression(trueExpression->getType()),
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001097 mCondition(cond),
1098 mTrueExpression(trueExpression),
1099 mFalseExpression(falseExpression)
1100{
1101 getTypePointer()->setQualifier(
1102 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1103}
1104
Olli Etuaho81629262017-04-19 11:56:01 +03001105TIntermLoop::TIntermLoop(TLoopType type,
1106 TIntermNode *init,
1107 TIntermTyped *cond,
1108 TIntermTyped *expr,
1109 TIntermBlock *body)
1110 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1111{
1112 // Declaration nodes with no children can appear if all the declarators just added constants to
1113 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1114 if (mInit && mInit->getAsDeclarationNode() &&
1115 mInit->getAsDeclarationNode()->getSequence()->empty())
1116 {
1117 mInit = nullptr;
1118 }
1119}
1120
Olli Etuaho923ecef2017-10-11 12:01:38 +03001121TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
1122 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
1123{
1124 // Prune empty false blocks so that there won't be unnecessary operations done on it.
1125 if (mFalseBlock && mFalseBlock->getSequence()->empty())
1126 {
1127 mFalseBlock = nullptr;
1128 }
1129}
1130
1131TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
1132 : TIntermNode(), mInit(init), mStatementList(statementList)
1133{
1134 ASSERT(mStatementList);
1135}
1136
1137void TIntermSwitch::setStatementList(TIntermBlock *statementList)
1138{
1139 ASSERT(statementList);
1140 mStatementList = statementList;
1141}
1142
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001143// static
1144TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1145 TIntermTyped *trueExpression,
1146 TIntermTyped *falseExpression)
1147{
1148 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1149 falseExpression->getQualifier() == EvqConst)
1150 {
1151 return EvqConst;
1152 }
1153 return EvqTemporary;
1154}
1155
Olli Etuaho765924f2018-01-04 12:48:36 +02001156TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001157{
1158 if (mCondition->getAsConstantUnion())
1159 {
1160 if (mCondition->getAsConstantUnion()->getBConst(0))
1161 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001162 return mTrueExpression;
1163 }
1164 else
1165 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001166 return mFalseExpression;
1167 }
1168 }
1169 return this;
1170}
1171
Olli Etuahob6fa0432016-09-28 16:28:05 +01001172void TIntermSwizzle::promote()
1173{
1174 TQualifier resultQualifier = EvqTemporary;
1175 if (mOperand->getQualifier() == EvqConst)
1176 resultQualifier = EvqConst;
1177
1178 auto numFields = mSwizzleOffsets.size();
1179 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1180 static_cast<unsigned char>(numFields)));
1181}
1182
1183bool TIntermSwizzle::hasDuplicateOffsets() const
1184{
1185 int offsetCount[4] = {0u, 0u, 0u, 0u};
1186 for (const auto offset : mSwizzleOffsets)
1187 {
1188 offsetCount[offset]++;
1189 if (offsetCount[offset] > 1)
1190 {
1191 return true;
1192 }
1193 }
1194 return false;
1195}
1196
Olli Etuaho09b04a22016-12-15 13:30:26 +00001197bool TIntermSwizzle::offsetsMatch(int offset) const
1198{
1199 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1200}
1201
Olli Etuahob6fa0432016-09-28 16:28:05 +01001202void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1203{
1204 for (const int offset : mSwizzleOffsets)
1205 {
1206 switch (offset)
1207 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001208 case 0:
1209 *out << "x";
1210 break;
1211 case 1:
1212 *out << "y";
1213 break;
1214 case 2:
1215 *out << "z";
1216 break;
1217 case 3:
1218 *out << "w";
1219 break;
1220 default:
1221 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001222 }
1223 }
1224}
1225
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001226TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1227 const TIntermTyped *left,
1228 const TIntermTyped *right)
1229{
1230 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1231 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1232 right->getQualifier() != EvqConst)
1233 {
1234 return EvqTemporary;
1235 }
1236 return EvqConst;
1237}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001238
1239// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001240void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001241{
Olli Etuaho1dded802016-08-18 18:13:13 +03001242 ASSERT(!isMultiplication() ||
1243 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1244
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001245 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1246 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001247 if (mOp == EOpComma)
1248 {
1249 setType(mRight->getType());
1250 return;
1251 }
1252
Jamie Madillb1a85f42014-08-19 15:23:24 -04001253 // Base assumption: just make the type the same as the left
1254 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001255 setType(mLeft->getType());
1256
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001257 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001258 // Binary operations results in temporary variables unless both
1259 // operands are const.
1260 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1261 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001262 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001263 getTypePointer()->setQualifier(EvqTemporary);
1264 }
1265
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001266 // Handle indexing ops.
1267 switch (mOp)
1268 {
1269 case EOpIndexDirect:
1270 case EOpIndexIndirect:
1271 if (mLeft->isArray())
1272 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001273 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001274 }
1275 else if (mLeft->isMatrix())
1276 {
1277 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1278 static_cast<unsigned char>(mLeft->getRows())));
1279 }
1280 else if (mLeft->isVector())
1281 {
1282 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1283 }
1284 else
1285 {
1286 UNREACHABLE();
1287 }
1288 return;
1289 case EOpIndexDirectStruct:
1290 {
1291 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1292 const int i = mRight->getAsConstantUnion()->getIConst(0);
1293 setType(*fields[i]->type());
1294 getTypePointer()->setQualifier(resultQualifier);
1295 return;
1296 }
1297 case EOpIndexDirectInterfaceBlock:
1298 {
1299 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1300 const int i = mRight->getAsConstantUnion()->getIConst(0);
1301 setType(*fields[i]->type());
1302 getTypePointer()->setQualifier(resultQualifier);
1303 return;
1304 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001305 default:
1306 break;
1307 }
1308
1309 ASSERT(mLeft->isArray() == mRight->isArray());
1310
1311 // The result gets promoted to the highest precision.
1312 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1313 getTypePointer()->setPrecision(higherPrecision);
1314
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001315 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001316
1317 //
1318 // All scalars or structs. Code after this test assumes this case is removed!
1319 //
1320 if (nominalSize == 1)
1321 {
1322 switch (mOp)
1323 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001324 //
1325 // Promote to conditional
1326 //
1327 case EOpEqual:
1328 case EOpNotEqual:
1329 case EOpLessThan:
1330 case EOpGreaterThan:
1331 case EOpLessThanEqual:
1332 case EOpGreaterThanEqual:
1333 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1334 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001335
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001336 //
1337 // And and Or operate on conditionals
1338 //
1339 case EOpLogicalAnd:
1340 case EOpLogicalXor:
1341 case EOpLogicalOr:
1342 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1343 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1344 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001345
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001346 default:
1347 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001348 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001349 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001350 }
1351
1352 // If we reach here, at least one of the operands is vector or matrix.
1353 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001354 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001355
Jamie Madillb1a85f42014-08-19 15:23:24 -04001356 switch (mOp)
1357 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001358 case EOpMul:
1359 break;
1360 case EOpMatrixTimesScalar:
1361 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001362 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001363 setType(TType(basicType, higherPrecision, resultQualifier,
1364 static_cast<unsigned char>(mRight->getCols()),
1365 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001366 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001367 break;
1368 case EOpMatrixTimesVector:
1369 setType(TType(basicType, higherPrecision, resultQualifier,
1370 static_cast<unsigned char>(mLeft->getRows()), 1));
1371 break;
1372 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001373 setType(TType(basicType, higherPrecision, resultQualifier,
1374 static_cast<unsigned char>(mRight->getCols()),
1375 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001376 break;
1377 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001378 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001379 static_cast<unsigned char>(nominalSize), 1));
1380 break;
1381 case EOpVectorTimesMatrix:
1382 setType(TType(basicType, higherPrecision, resultQualifier,
1383 static_cast<unsigned char>(mRight->getCols()), 1));
1384 break;
1385 case EOpMulAssign:
1386 case EOpVectorTimesScalarAssign:
1387 case EOpVectorTimesMatrixAssign:
1388 case EOpMatrixTimesScalarAssign:
1389 case EOpMatrixTimesMatrixAssign:
1390 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1391 break;
1392 case EOpAssign:
1393 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001394 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1395 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1396 break;
1397 case EOpAdd:
1398 case EOpSub:
1399 case EOpDiv:
1400 case EOpIMod:
1401 case EOpBitShiftLeft:
1402 case EOpBitShiftRight:
1403 case EOpBitwiseAnd:
1404 case EOpBitwiseXor:
1405 case EOpBitwiseOr:
1406 case EOpAddAssign:
1407 case EOpSubAssign:
1408 case EOpDivAssign:
1409 case EOpIModAssign:
1410 case EOpBitShiftLeftAssign:
1411 case EOpBitShiftRightAssign:
1412 case EOpBitwiseAndAssign:
1413 case EOpBitwiseXorAssign:
1414 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001415 {
1416 const int secondarySize =
1417 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1418 setType(TType(basicType, higherPrecision, resultQualifier,
1419 static_cast<unsigned char>(nominalSize),
1420 static_cast<unsigned char>(secondarySize)));
1421 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001422 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001423 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001424 case EOpEqual:
1425 case EOpNotEqual:
1426 case EOpLessThan:
1427 case EOpGreaterThan:
1428 case EOpLessThanEqual:
1429 case EOpGreaterThanEqual:
1430 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1431 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001432 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001433 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001434
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001435 case EOpIndexDirect:
1436 case EOpIndexIndirect:
1437 case EOpIndexDirectInterfaceBlock:
1438 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001439 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001440 UNREACHABLE();
1441 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001442 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001443 UNREACHABLE();
1444 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001445 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001446}
1447
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001448bool TIntermConstantUnion::hasConstantValue() const
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001449{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001450 return true;
1451}
1452
1453const TConstantUnion *TIntermConstantUnion::getConstantValue() const
1454{
1455 return mUnionArrayPointer;
1456}
1457
1458const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
1459 const TConstantUnion *constArray,
1460 int index)
1461{
1462 if (type.isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001463 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001464 ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
1465 TType arrayElementType(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001466 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001467 size_t arrayElementSize = arrayElementType.getObjectSize();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001468 return &constArray[arrayElementSize * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001469 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001470 else if (type.isMatrix())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001471 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001472 ASSERT(index < type.getCols());
1473 int size = type.getRows();
1474 return &constArray[size * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001475 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001476 else if (type.isVector())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001477 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001478 ASSERT(index < type.getNominalSize());
1479 return &constArray[index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001480 }
1481 else
1482 {
1483 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001484 return nullptr;
1485 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001486}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001487
Olli Etuaho765924f2018-01-04 12:48:36 +02001488TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001489{
1490 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1491 if (operandConstant == nullptr)
1492 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001493 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001494 }
1495
1496 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1497 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1498 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001499 constArray[i] = *TIntermConstantUnion::FoldIndexing(
1500 operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
Olli Etuahob6fa0432016-09-28 16:28:05 +01001501 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001502 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001503}
1504
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001505TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1506{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001507 const TConstantUnion *rightConstant = mRight->getConstantValue();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001508 switch (mOp)
1509 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001510 case EOpComma:
1511 {
1512 if (mLeft->hasSideEffects())
1513 {
1514 return this;
1515 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001516 return mRight;
1517 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001518 case EOpIndexDirect:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001519 case EOpIndexDirectStruct:
1520 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001521 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001522 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001523 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001524 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001525 size_t index = static_cast<size_t>(rightConstant->getIConst());
1526 TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
1527 if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
1528 !leftAggregate->hasSideEffects())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001529 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001530 ASSERT(index < leftAggregate->getSequence()->size());
1531 // This transformation can't add complexity as we're eliminating the constructor
1532 // entirely.
1533 return leftAggregate->getSequence()->at(index)->getAsTyped();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001534 }
1535
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001536 // If the indexed value is already a constant union, we can't increase duplication of
1537 // data by folding the indexing. Also fold the node in case it's generally beneficial to
1538 // replace this type of node with a constant union even if that would mean duplicating
1539 // data.
1540 if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
1541 {
1542 const TConstantUnion *constantValue = getConstantValue();
1543 if (constantValue == nullptr)
1544 {
1545 return this;
1546 }
1547 return CreateFoldedNode(constantValue, this);
1548 }
1549 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001550 }
1551 case EOpIndexIndirect:
1552 case EOpIndexDirectInterfaceBlock:
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001553 case EOpInitialize:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001554 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001555 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001556 default:
1557 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001558 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001559 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001560 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001561 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001562 const TConstantUnion *leftConstant = mLeft->getConstantValue();
1563 if (leftConstant == nullptr)
1564 {
1565 return this;
1566 }
1567 const TConstantUnion *constArray =
1568 TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
1569 mRight->getType(), diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001570 if (!constArray)
1571 {
1572 return this;
1573 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001574 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001575 }
1576 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001577}
1578
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001579bool TIntermBinary::hasConstantValue() const
1580{
1581 switch (mOp)
1582 {
1583 case EOpIndexDirect:
1584 case EOpIndexDirectStruct:
1585 {
1586 if (mLeft->hasConstantValue() && mRight->hasConstantValue())
1587 {
1588 return true;
1589 }
1590 }
1591 default:
1592 break;
1593 }
1594 return false;
1595}
1596
1597const TConstantUnion *TIntermBinary::getConstantValue() const
1598{
1599 if (!hasConstantValue())
1600 {
1601 return nullptr;
1602 }
1603
1604 const TConstantUnion *leftConstantValue = mLeft->getConstantValue();
1605 int index = mRight->getConstantValue()->getIConst();
1606 const TConstantUnion *constIndexingResult = nullptr;
1607 if (mOp == EOpIndexDirect)
1608 {
1609 constIndexingResult =
1610 TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
1611 }
1612 else
1613 {
1614 ASSERT(mOp == EOpIndexDirectStruct);
1615 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1616
1617 size_t previousFieldsSize = 0;
1618 for (int i = 0; i < index; ++i)
1619 {
1620 previousFieldsSize += fields[i]->type()->getObjectSize();
1621 }
1622 constIndexingResult = leftConstantValue + previousFieldsSize;
1623 }
1624 return constIndexingResult;
1625}
1626
Olli Etuahof119a262016-08-19 15:54:22 +03001627TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001628{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301629 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001630
1631 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301632 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001633 // The size of runtime-sized arrays may only be determined at runtime.
1634 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001635 {
1636 return this;
1637 }
1638 constArray = new TConstantUnion[1];
1639 constArray->setIConst(mOperand->getOutermostArraySize());
1640 }
1641 else
1642 {
1643 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1644 if (operandConstant == nullptr)
1645 {
1646 return this;
1647 }
1648
1649 switch (mOp)
1650 {
1651 case EOpAny:
1652 case EOpAll:
1653 case EOpLength:
1654 case EOpTranspose:
1655 case EOpDeterminant:
1656 case EOpInverse:
1657 case EOpPackSnorm2x16:
1658 case EOpUnpackSnorm2x16:
1659 case EOpPackUnorm2x16:
1660 case EOpUnpackUnorm2x16:
1661 case EOpPackHalf2x16:
1662 case EOpUnpackHalf2x16:
1663 case EOpPackUnorm4x8:
1664 case EOpPackSnorm4x8:
1665 case EOpUnpackUnorm4x8:
1666 case EOpUnpackSnorm4x8:
1667 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1668 break;
1669 default:
1670 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1671 break;
1672 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301673 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001674 if (constArray == nullptr)
1675 {
1676 return this;
1677 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001678 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001679}
1680
Olli Etuahof119a262016-08-19 15:54:22 +03001681TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001682{
1683 // Make sure that all params are constant before actual constant folding.
1684 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001685 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001686 if (param->getAsConstantUnion() == nullptr)
1687 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001688 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001689 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001690 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001691 const TConstantUnion *constArray = nullptr;
Olli Etuaho1d122782015-11-06 15:35:17 +02001692 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001693 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001694 if (mType.canReplaceWithConstantUnion())
Olli Etuaho765924f2018-01-04 12:48:36 +02001695 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001696 constArray = getConstantValue();
Olli Etuaho765924f2018-01-04 12:48:36 +02001697 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001698 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001699 else if (CanFoldAggregateBuiltInOp(mOp))
Olli Etuaho2768bc82017-12-12 11:51:48 +02001700 {
Olli Etuahof119a262016-08-19 15:54:22 +03001701 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001702 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001703 if (constArray == nullptr)
1704 {
1705 return this;
1706 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001707 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001708}
1709
Jamie Madillb1a85f42014-08-19 15:23:24 -04001710//
1711// The fold functions see if an operation on a constant can be done in place,
1712// without generating run-time code.
1713//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001714// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001715//
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001716const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
1717 const TConstantUnion *leftArray,
1718 const TType &leftType,
1719 const TConstantUnion *rightArray,
1720 const TType &rightType,
1721 TDiagnostics *diagnostics,
1722 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001723{
Olli Etuahof119a262016-08-19 15:54:22 +03001724 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001725
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001726 size_t objectSize = leftType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001727
1728 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001729 if (rightType.getObjectSize() == 1 && objectSize > 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001730 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001731 rightArray = Vectorize(*rightArray, objectSize);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001732 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001733 else if (rightType.getObjectSize() > 1 && objectSize == 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001734 {
1735 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001736 leftArray = Vectorize(*leftArray, rightType.getObjectSize());
1737 objectSize = rightType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001738 }
1739
1740 TConstantUnion *resultArray = nullptr;
1741
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001742 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001743 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001744 case EOpAdd:
1745 resultArray = new TConstantUnion[objectSize];
1746 for (size_t i = 0; i < objectSize; i++)
1747 resultArray[i] =
1748 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1749 break;
1750 case EOpSub:
1751 resultArray = new TConstantUnion[objectSize];
1752 for (size_t i = 0; i < objectSize; i++)
1753 resultArray[i] =
1754 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1755 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001756
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001757 case EOpMul:
1758 case EOpVectorTimesScalar:
1759 case EOpMatrixTimesScalar:
1760 resultArray = new TConstantUnion[objectSize];
1761 for (size_t i = 0; i < objectSize; i++)
1762 resultArray[i] =
1763 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1764 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001765
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001766 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001767 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001768 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001769 ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001770
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001771 const int leftCols = leftType.getCols();
1772 const int leftRows = leftType.getRows();
1773 const int rightCols = rightType.getCols();
1774 const int rightRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001775 const int resultCols = rightCols;
1776 const int resultRows = leftRows;
1777
1778 resultArray = new TConstantUnion[resultCols * resultRows];
1779 for (int row = 0; row < resultRows; row++)
1780 {
1781 for (int column = 0; column < resultCols; column++)
1782 {
1783 resultArray[resultRows * column + row].setFConst(0.0f);
1784 for (int i = 0; i < leftCols; i++)
1785 {
1786 resultArray[resultRows * column + row].setFConst(
1787 resultArray[resultRows * column + row].getFConst() +
1788 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001789 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001790 }
1791 }
1792 }
1793 }
1794 break;
1795
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001796 case EOpDiv:
1797 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001798 {
1799 resultArray = new TConstantUnion[objectSize];
1800 for (size_t i = 0; i < objectSize; i++)
1801 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001802 switch (leftType.getBasicType())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001803 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001804 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001805 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001806 ASSERT(op == EOpDiv);
1807 float dividend = leftArray[i].getFConst();
1808 float divisor = rightArray[i].getFConst();
1809 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001810 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001811 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001812 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001813 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001814 line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001815 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001816 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001817 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001818 }
1819 else
1820 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001821 diagnostics->warning(line, "Divide by zero during constant folding",
1822 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001823 bool negativeResult =
1824 std::signbit(dividend) != std::signbit(divisor);
1825 resultArray[i].setFConst(
1826 negativeResult ? -std::numeric_limits<float>::infinity()
1827 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001828 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001829 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001830 else if (gl::isInf(dividend) && gl::isInf(divisor))
1831 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001832 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001833 "Infinity divided by infinity during constant "
1834 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001835 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001836 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1837 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001838 else
1839 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001840 float result = dividend / divisor;
1841 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001842 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001843 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001844 line, "Constant folded division overflowed to infinity", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001845 }
1846 resultArray[i].setFConst(result);
1847 }
1848 break;
1849 }
1850 case EbtInt:
1851 if (rightArray[i] == 0)
1852 {
1853 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001854 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001855 resultArray[i].setIConst(INT_MAX);
1856 }
1857 else
1858 {
1859 int lhs = leftArray[i].getIConst();
1860 int divisor = rightArray[i].getIConst();
1861 if (op == EOpDiv)
1862 {
1863 // Check for the special case where the minimum representable number
1864 // is
1865 // divided by -1. If left alone this leads to integer overflow in
1866 // C++.
1867 // ESSL 3.00.6 section 4.1.3 Integers:
1868 // "However, for the case where the minimum representable value is
1869 // divided by -1, it is allowed to return either the minimum
1870 // representable value or the maximum representable value."
1871 if (lhs == -0x7fffffff - 1 && divisor == -1)
1872 {
1873 resultArray[i].setIConst(0x7fffffff);
1874 }
1875 else
1876 {
1877 resultArray[i].setIConst(lhs / divisor);
1878 }
Olli Etuahod4453572016-09-27 13:21:46 +01001879 }
1880 else
1881 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001882 ASSERT(op == EOpIMod);
1883 if (lhs < 0 || divisor < 0)
1884 {
1885 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1886 // when
1887 // either one of the operands is negative.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001888 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001889 "Negative modulus operator operand "
1890 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001891 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001892 resultArray[i].setIConst(0);
1893 }
1894 else
1895 {
1896 resultArray[i].setIConst(lhs % divisor);
1897 }
Olli Etuahod4453572016-09-27 13:21:46 +01001898 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001899 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001900 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001901
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001902 case EbtUInt:
1903 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001904 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001905 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001906 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001907 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001908 }
1909 else
1910 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001911 if (op == EOpDiv)
1912 {
1913 resultArray[i].setUConst(leftArray[i].getUConst() /
1914 rightArray[i].getUConst());
1915 }
1916 else
1917 {
1918 ASSERT(op == EOpIMod);
1919 resultArray[i].setUConst(leftArray[i].getUConst() %
1920 rightArray[i].getUConst());
1921 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001922 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001923 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001924
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001925 default:
1926 UNREACHABLE();
1927 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001928 }
1929 }
1930 }
1931 break;
1932
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001933 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001934 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001935 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001936 ASSERT(rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001937
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001938 const int matrixCols = leftType.getCols();
1939 const int matrixRows = leftType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001940
1941 resultArray = new TConstantUnion[matrixRows];
1942
1943 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1944 {
1945 resultArray[matrixRow].setFConst(0.0f);
1946 for (int col = 0; col < matrixCols; col++)
1947 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001948 resultArray[matrixRow].setFConst(
1949 resultArray[matrixRow].getFConst() +
1950 leftArray[col * matrixRows + matrixRow].getFConst() *
1951 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001952 }
1953 }
1954 }
1955 break;
1956
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001957 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001958 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001959 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001960 ASSERT(leftType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001961
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001962 const int matrixCols = rightType.getCols();
1963 const int matrixRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001964
1965 resultArray = new TConstantUnion[matrixCols];
1966
1967 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1968 {
1969 resultArray[matrixCol].setFConst(0.0f);
1970 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1971 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001972 resultArray[matrixCol].setFConst(
1973 resultArray[matrixCol].getFConst() +
1974 leftArray[matrixRow].getFConst() *
1975 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001976 }
1977 }
1978 }
1979 break;
1980
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001981 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001982 {
1983 resultArray = new TConstantUnion[objectSize];
1984 for (size_t i = 0; i < objectSize; i++)
1985 {
1986 resultArray[i] = leftArray[i] && rightArray[i];
1987 }
1988 }
1989 break;
1990
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001991 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001992 {
1993 resultArray = new TConstantUnion[objectSize];
1994 for (size_t i = 0; i < objectSize; i++)
1995 {
1996 resultArray[i] = leftArray[i] || rightArray[i];
1997 }
1998 }
1999 break;
2000
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002001 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002002 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002003 ASSERT(leftType.getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002004 resultArray = new TConstantUnion[objectSize];
2005 for (size_t i = 0; i < objectSize; i++)
2006 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03002007 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002008 }
2009 }
2010 break;
2011
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002012 case EOpBitwiseAnd:
2013 resultArray = new TConstantUnion[objectSize];
2014 for (size_t i = 0; i < objectSize; i++)
2015 resultArray[i] = leftArray[i] & rightArray[i];
2016 break;
2017 case EOpBitwiseXor:
2018 resultArray = new TConstantUnion[objectSize];
2019 for (size_t i = 0; i < objectSize; i++)
2020 resultArray[i] = leftArray[i] ^ rightArray[i];
2021 break;
2022 case EOpBitwiseOr:
2023 resultArray = new TConstantUnion[objectSize];
2024 for (size_t i = 0; i < objectSize; i++)
2025 resultArray[i] = leftArray[i] | rightArray[i];
2026 break;
2027 case EOpBitShiftLeft:
2028 resultArray = new TConstantUnion[objectSize];
2029 for (size_t i = 0; i < objectSize; i++)
2030 resultArray[i] =
2031 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
2032 break;
2033 case EOpBitShiftRight:
2034 resultArray = new TConstantUnion[objectSize];
2035 for (size_t i = 0; i < objectSize; i++)
2036 resultArray[i] =
2037 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
2038 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002039
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002040 case EOpLessThan:
2041 ASSERT(objectSize == 1);
2042 resultArray = new TConstantUnion[1];
2043 resultArray->setBConst(*leftArray < *rightArray);
2044 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002045
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002046 case EOpGreaterThan:
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 EOpLessThanEqual:
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 EOpGreaterThanEqual:
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 EOpEqual:
2065 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002066 {
2067 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002068 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002069 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002070 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002071 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002072 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002073 equal = false;
2074 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002075 }
2076 }
2077 if (op == EOpEqual)
2078 {
2079 resultArray->setBConst(equal);
2080 }
2081 else
2082 {
2083 resultArray->setBConst(!equal);
2084 }
2085 }
2086 break;
2087
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002088 default:
2089 UNREACHABLE();
2090 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002091 }
2092 return resultArray;
2093}
2094
Olli Etuahof119a262016-08-19 15:54:22 +03002095// The fold functions do operations on a constant at GLSL compile time, without generating run-time
2096// code. Returns the constant value to keep using. Nullptr should not be returned.
2097TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04002098{
Olli Etuahof119a262016-08-19 15:54:22 +03002099 // Do operations where the return type may have a different number of components compared to the
2100 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04002101
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002102 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002103 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302104
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002105 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302106 TConstantUnion *resultArray = nullptr;
2107 switch (op)
2108 {
Olli Etuahof119a262016-08-19 15:54:22 +03002109 case EOpAny:
2110 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302111 resultArray = new TConstantUnion();
2112 resultArray->setBConst(false);
2113 for (size_t i = 0; i < objectSize; i++)
2114 {
2115 if (operandArray[i].getBConst())
2116 {
2117 resultArray->setBConst(true);
2118 break;
2119 }
2120 }
2121 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302122
Olli Etuahof119a262016-08-19 15:54:22 +03002123 case EOpAll:
2124 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302125 resultArray = new TConstantUnion();
2126 resultArray->setBConst(true);
2127 for (size_t i = 0; i < objectSize; i++)
2128 {
2129 if (!operandArray[i].getBConst())
2130 {
2131 resultArray->setBConst(false);
2132 break;
2133 }
2134 }
2135 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136
Olli Etuahof119a262016-08-19 15:54:22 +03002137 case EOpLength:
2138 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302139 resultArray = new TConstantUnion();
2140 resultArray->setFConst(VectorLength(operandArray, objectSize));
2141 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302142
Olli Etuahof119a262016-08-19 15:54:22 +03002143 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302144 {
Olli Etuahof119a262016-08-19 15:54:22 +03002145 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302146 resultArray = new TConstantUnion[objectSize];
2147 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002148 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302149 SetUnionArrayFromMatrix(result, resultArray);
2150 break;
2151 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302152
Olli Etuahof119a262016-08-19 15:54:22 +03002153 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302154 {
Olli Etuahof119a262016-08-19 15:54:22 +03002155 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302156 unsigned int size = getType().getNominalSize();
2157 ASSERT(size >= 2 && size <= 4);
2158 resultArray = new TConstantUnion();
2159 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
2160 break;
2161 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302162
Olli Etuahof119a262016-08-19 15:54:22 +03002163 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302164 {
Olli Etuahof119a262016-08-19 15:54:22 +03002165 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302166 unsigned int size = getType().getNominalSize();
2167 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03002168 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05302169 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
2170 SetUnionArrayFromMatrix(result, resultArray);
2171 break;
2172 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302173
Olli Etuahof119a262016-08-19 15:54:22 +03002174 case EOpPackSnorm2x16:
2175 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302176 ASSERT(getType().getNominalSize() == 2);
2177 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002178 resultArray->setUConst(
2179 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302180 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302181
Olli Etuahof119a262016-08-19 15:54:22 +03002182 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302183 {
Olli Etuahof119a262016-08-19 15:54:22 +03002184 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302185 resultArray = new TConstantUnion[2];
2186 float f1, f2;
2187 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2188 resultArray[0].setFConst(f1);
2189 resultArray[1].setFConst(f2);
2190 break;
2191 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302192
Olli Etuahof119a262016-08-19 15:54:22 +03002193 case EOpPackUnorm2x16:
2194 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302195 ASSERT(getType().getNominalSize() == 2);
2196 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002197 resultArray->setUConst(
2198 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302199 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302200
Olli Etuahof119a262016-08-19 15:54:22 +03002201 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302202 {
Olli Etuahof119a262016-08-19 15:54:22 +03002203 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302204 resultArray = new TConstantUnion[2];
2205 float f1, f2;
2206 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2207 resultArray[0].setFConst(f1);
2208 resultArray[1].setFConst(f2);
2209 break;
2210 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302211
Olli Etuahof119a262016-08-19 15:54:22 +03002212 case EOpPackHalf2x16:
2213 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302214 ASSERT(getType().getNominalSize() == 2);
2215 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002216 resultArray->setUConst(
2217 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302218 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302219
Olli Etuahof119a262016-08-19 15:54:22 +03002220 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302221 {
Olli Etuahof119a262016-08-19 15:54:22 +03002222 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302223 resultArray = new TConstantUnion[2];
2224 float f1, f2;
2225 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2226 resultArray[0].setFConst(f1);
2227 resultArray[1].setFConst(f2);
2228 break;
2229 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302230
Olli Etuaho25aef452017-01-29 16:15:44 -08002231 case EOpPackUnorm4x8:
2232 {
2233 ASSERT(getType().getBasicType() == EbtFloat);
2234 resultArray = new TConstantUnion();
2235 resultArray->setUConst(
2236 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2237 operandArray[2].getFConst(), operandArray[3].getFConst()));
2238 break;
2239 }
2240 case EOpPackSnorm4x8:
2241 {
2242 ASSERT(getType().getBasicType() == EbtFloat);
2243 resultArray = new TConstantUnion();
2244 resultArray->setUConst(
2245 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2246 operandArray[2].getFConst(), operandArray[3].getFConst()));
2247 break;
2248 }
2249 case EOpUnpackUnorm4x8:
2250 {
2251 ASSERT(getType().getBasicType() == EbtUInt);
2252 resultArray = new TConstantUnion[4];
2253 float f[4];
2254 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2255 for (size_t i = 0; i < 4; ++i)
2256 {
2257 resultArray[i].setFConst(f[i]);
2258 }
2259 break;
2260 }
2261 case EOpUnpackSnorm4x8:
2262 {
2263 ASSERT(getType().getBasicType() == EbtUInt);
2264 resultArray = new TConstantUnion[4];
2265 float f[4];
2266 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2267 for (size_t i = 0; i < 4; ++i)
2268 {
2269 resultArray[i].setFConst(f[i]);
2270 }
2271 break;
2272 }
2273
Olli Etuahof119a262016-08-19 15:54:22 +03002274 default:
2275 UNREACHABLE();
2276 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302277 }
2278
2279 return resultArray;
2280}
2281
Olli Etuahof119a262016-08-19 15:54:22 +03002282TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2283 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302284{
Olli Etuahof119a262016-08-19 15:54:22 +03002285 // Do unary operations where each component of the result is computed based on the corresponding
2286 // component of the operand. Also folds normalize, though the divisor in that case takes all
2287 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302288
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002289 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002290 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002291
2292 size_t objectSize = getType().getObjectSize();
2293
Arun Patoleab2b9a22015-07-06 18:27:56 +05302294 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2295 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302296 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002297 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302298 {
Olli Etuahof119a262016-08-19 15:54:22 +03002299 case EOpNegative:
2300 switch (getType().getBasicType())
2301 {
2302 case EbtFloat:
2303 resultArray[i].setFConst(-operandArray[i].getFConst());
2304 break;
2305 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002306 if (operandArray[i] == std::numeric_limits<int>::min())
2307 {
2308 // The minimum representable integer doesn't have a positive
2309 // counterpart, rather the negation overflows and in ESSL is supposed to
2310 // wrap back to the minimum representable integer. Make sure that we
2311 // don't actually let the negation overflow, which has undefined
2312 // behavior in C++.
2313 resultArray[i].setIConst(std::numeric_limits<int>::min());
2314 }
2315 else
2316 {
2317 resultArray[i].setIConst(-operandArray[i].getIConst());
2318 }
Olli Etuahof119a262016-08-19 15:54:22 +03002319 break;
2320 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002321 if (operandArray[i] == 0x80000000u)
2322 {
2323 resultArray[i].setUConst(0x80000000u);
2324 }
2325 else
2326 {
2327 resultArray[i].setUConst(static_cast<unsigned int>(
2328 -static_cast<int>(operandArray[i].getUConst())));
2329 }
Olli Etuahof119a262016-08-19 15:54:22 +03002330 break;
2331 default:
2332 UNREACHABLE();
2333 return nullptr;
2334 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302335 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302336
Olli Etuahof119a262016-08-19 15:54:22 +03002337 case EOpPositive:
2338 switch (getType().getBasicType())
2339 {
2340 case EbtFloat:
2341 resultArray[i].setFConst(operandArray[i].getFConst());
2342 break;
2343 case EbtInt:
2344 resultArray[i].setIConst(operandArray[i].getIConst());
2345 break;
2346 case EbtUInt:
2347 resultArray[i].setUConst(static_cast<unsigned int>(
2348 static_cast<int>(operandArray[i].getUConst())));
2349 break;
2350 default:
2351 UNREACHABLE();
2352 return nullptr;
2353 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302354 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302355
Olli Etuahof119a262016-08-19 15:54:22 +03002356 case EOpLogicalNot:
2357 switch (getType().getBasicType())
2358 {
2359 case EbtBool:
2360 resultArray[i].setBConst(!operandArray[i].getBConst());
2361 break;
2362 default:
2363 UNREACHABLE();
2364 return nullptr;
2365 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302366 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302367
Olli Etuahof119a262016-08-19 15:54:22 +03002368 case EOpBitwiseNot:
2369 switch (getType().getBasicType())
2370 {
2371 case EbtInt:
2372 resultArray[i].setIConst(~operandArray[i].getIConst());
2373 break;
2374 case EbtUInt:
2375 resultArray[i].setUConst(~operandArray[i].getUConst());
2376 break;
2377 default:
2378 UNREACHABLE();
2379 return nullptr;
2380 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302381 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302382
Olli Etuahof119a262016-08-19 15:54:22 +03002383 case EOpRadians:
2384 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302385 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2386 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302387
Olli Etuahof119a262016-08-19 15:54:22 +03002388 case EOpDegrees:
2389 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302390 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2391 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302392
Olli Etuahof119a262016-08-19 15:54:22 +03002393 case EOpSin:
2394 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302395 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302396
Olli Etuahof119a262016-08-19 15:54:22 +03002397 case EOpCos:
2398 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2399 break;
2400
2401 case EOpTan:
2402 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2403 break;
2404
2405 case EOpAsin:
2406 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2407 // 0.
2408 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2409 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2410 diagnostics, &resultArray[i]);
2411 else
2412 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2413 break;
2414
2415 case EOpAcos:
2416 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2417 // 0.
2418 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2419 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2420 diagnostics, &resultArray[i]);
2421 else
2422 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2423 break;
2424
2425 case EOpAtan:
2426 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2427 break;
2428
2429 case EOpSinh:
2430 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2431 break;
2432
2433 case EOpCosh:
2434 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2435 break;
2436
2437 case EOpTanh:
2438 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2439 break;
2440
2441 case EOpAsinh:
2442 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2443 break;
2444
2445 case EOpAcosh:
2446 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2447 if (operandArray[i].getFConst() < 1.0f)
2448 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2449 diagnostics, &resultArray[i]);
2450 else
2451 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2452 break;
2453
2454 case EOpAtanh:
2455 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2456 // 0.
2457 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2458 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2459 diagnostics, &resultArray[i]);
2460 else
2461 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2462 break;
2463
2464 case EOpAbs:
2465 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302466 {
Olli Etuahof119a262016-08-19 15:54:22 +03002467 case EbtFloat:
2468 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2469 break;
2470 case EbtInt:
2471 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2472 break;
2473 default:
2474 UNREACHABLE();
2475 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302476 }
2477 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002478
2479 case EOpSign:
2480 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302481 {
Olli Etuahof119a262016-08-19 15:54:22 +03002482 case EbtFloat:
2483 {
2484 float fConst = operandArray[i].getFConst();
2485 float fResult = 0.0f;
2486 if (fConst > 0.0f)
2487 fResult = 1.0f;
2488 else if (fConst < 0.0f)
2489 fResult = -1.0f;
2490 resultArray[i].setFConst(fResult);
2491 break;
2492 }
2493 case EbtInt:
2494 {
2495 int iConst = operandArray[i].getIConst();
2496 int iResult = 0;
2497 if (iConst > 0)
2498 iResult = 1;
2499 else if (iConst < 0)
2500 iResult = -1;
2501 resultArray[i].setIConst(iResult);
2502 break;
2503 }
2504 default:
2505 UNREACHABLE();
2506 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302507 }
2508 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302509
Olli Etuahof119a262016-08-19 15:54:22 +03002510 case EOpFloor:
2511 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2512 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302513
Olli Etuahof119a262016-08-19 15:54:22 +03002514 case EOpTrunc:
2515 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2516 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302517
Olli Etuahof119a262016-08-19 15:54:22 +03002518 case EOpRound:
2519 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2520 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302521
Olli Etuahof119a262016-08-19 15:54:22 +03002522 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302523 {
Olli Etuahof119a262016-08-19 15:54:22 +03002524 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302525 float x = operandArray[i].getFConst();
2526 float result;
2527 float fractPart = modff(x, &result);
2528 if (fabsf(fractPart) == 0.5f)
2529 result = 2.0f * roundf(x / 2.0f);
2530 else
2531 result = roundf(x);
2532 resultArray[i].setFConst(result);
2533 break;
2534 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302535
Olli Etuahof119a262016-08-19 15:54:22 +03002536 case EOpCeil:
2537 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2538 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302539
Olli Etuahof119a262016-08-19 15:54:22 +03002540 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302541 {
Olli Etuahof119a262016-08-19 15:54:22 +03002542 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302543 float x = operandArray[i].getFConst();
2544 resultArray[i].setFConst(x - floorf(x));
2545 break;
2546 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302547
Olli Etuahof119a262016-08-19 15:54:22 +03002548 case EOpIsNan:
2549 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302550 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2551 break;
Arun Patole551279e2015-07-07 18:18:23 +05302552
Olli Etuahof119a262016-08-19 15:54:22 +03002553 case EOpIsInf:
2554 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302555 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2556 break;
Arun Patole551279e2015-07-07 18:18:23 +05302557
Olli Etuahof119a262016-08-19 15:54:22 +03002558 case EOpFloatBitsToInt:
2559 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302560 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2561 break;
Arun Patole551279e2015-07-07 18:18:23 +05302562
Olli Etuahof119a262016-08-19 15:54:22 +03002563 case EOpFloatBitsToUint:
2564 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302565 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2566 break;
Arun Patole551279e2015-07-07 18:18:23 +05302567
Olli Etuahof119a262016-08-19 15:54:22 +03002568 case EOpIntBitsToFloat:
2569 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302570 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2571 break;
Arun Patole551279e2015-07-07 18:18:23 +05302572
Olli Etuahof119a262016-08-19 15:54:22 +03002573 case EOpUintBitsToFloat:
2574 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302575 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2576 break;
Arun Patole551279e2015-07-07 18:18:23 +05302577
Olli Etuahof119a262016-08-19 15:54:22 +03002578 case EOpExp:
2579 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2580 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302581
Olli Etuahof119a262016-08-19 15:54:22 +03002582 case EOpLog:
2583 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2584 if (operandArray[i].getFConst() <= 0.0f)
2585 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2586 diagnostics, &resultArray[i]);
2587 else
2588 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2589 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302590
Olli Etuahof119a262016-08-19 15:54:22 +03002591 case EOpExp2:
2592 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2593 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302594
Olli Etuahof119a262016-08-19 15:54:22 +03002595 case EOpLog2:
2596 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2597 // And log2f is not available on some plarforms like old android, so just using
2598 // log(x)/log(2) here.
2599 if (operandArray[i].getFConst() <= 0.0f)
2600 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2601 diagnostics, &resultArray[i]);
2602 else
2603 {
2604 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2605 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2606 }
2607 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302608
Olli Etuahof119a262016-08-19 15:54:22 +03002609 case EOpSqrt:
2610 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2611 if (operandArray[i].getFConst() < 0.0f)
2612 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2613 diagnostics, &resultArray[i]);
2614 else
2615 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2616 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302617
Olli Etuahof119a262016-08-19 15:54:22 +03002618 case EOpInverseSqrt:
2619 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2620 // so getting the square root first using builtin function sqrt() and then taking
2621 // its inverse.
2622 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2623 // result to 0.
2624 if (operandArray[i].getFConst() <= 0.0f)
2625 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2626 diagnostics, &resultArray[i]);
2627 else
2628 {
2629 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2630 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2631 }
2632 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302633
Olli Etuahod68924e2017-01-02 17:34:40 +00002634 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002635 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302636 resultArray[i].setBConst(!operandArray[i].getBConst());
2637 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302638
Olli Etuahof119a262016-08-19 15:54:22 +03002639 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302640 {
Olli Etuahof119a262016-08-19 15:54:22 +03002641 ASSERT(getType().getBasicType() == EbtFloat);
2642 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302643 float length = VectorLength(operandArray, objectSize);
2644 if (length)
2645 resultArray[i].setFConst(x / length);
2646 else
Olli Etuahof119a262016-08-19 15:54:22 +03002647 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2648 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302649 break;
2650 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002651 case EOpBitfieldReverse:
2652 {
2653 uint32_t value;
2654 if (getType().getBasicType() == EbtInt)
2655 {
2656 value = static_cast<uint32_t>(operandArray[i].getIConst());
2657 }
2658 else
2659 {
2660 ASSERT(getType().getBasicType() == EbtUInt);
2661 value = operandArray[i].getUConst();
2662 }
2663 uint32_t result = gl::BitfieldReverse(value);
2664 if (getType().getBasicType() == EbtInt)
2665 {
2666 resultArray[i].setIConst(static_cast<int32_t>(result));
2667 }
2668 else
2669 {
2670 resultArray[i].setUConst(result);
2671 }
2672 break;
2673 }
2674 case EOpBitCount:
2675 {
2676 uint32_t value;
2677 if (getType().getBasicType() == EbtInt)
2678 {
2679 value = static_cast<uint32_t>(operandArray[i].getIConst());
2680 }
2681 else
2682 {
2683 ASSERT(getType().getBasicType() == EbtUInt);
2684 value = operandArray[i].getUConst();
2685 }
2686 int result = gl::BitCount(value);
2687 resultArray[i].setIConst(result);
2688 break;
2689 }
2690 case EOpFindLSB:
2691 {
2692 uint32_t value;
2693 if (getType().getBasicType() == EbtInt)
2694 {
2695 value = static_cast<uint32_t>(operandArray[i].getIConst());
2696 }
2697 else
2698 {
2699 ASSERT(getType().getBasicType() == EbtUInt);
2700 value = operandArray[i].getUConst();
2701 }
2702 resultArray[i].setIConst(gl::FindLSB(value));
2703 break;
2704 }
2705 case EOpFindMSB:
2706 {
2707 uint32_t value;
2708 if (getType().getBasicType() == EbtInt)
2709 {
2710 int intValue = operandArray[i].getIConst();
2711 value = static_cast<uint32_t>(intValue);
2712 if (intValue < 0)
2713 {
2714 // Look for zero instead of one in value. This also handles the intValue ==
2715 // -1 special case, where the return value needs to be -1.
2716 value = ~value;
2717 }
2718 }
2719 else
2720 {
2721 ASSERT(getType().getBasicType() == EbtUInt);
2722 value = operandArray[i].getUConst();
2723 }
2724 resultArray[i].setIConst(gl::FindMSB(value));
2725 break;
2726 }
Olli Etuahof119a262016-08-19 15:54:22 +03002727 case EOpDFdx:
2728 case EOpDFdy:
2729 case EOpFwidth:
2730 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302731 // Derivatives of constant arguments should be 0.
2732 resultArray[i].setFConst(0.0f);
2733 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302734
Olli Etuahof119a262016-08-19 15:54:22 +03002735 default:
2736 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302737 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302738 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002739
Arun Patoleab2b9a22015-07-06 18:27:56 +05302740 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002741}
2742
Olli Etuahof119a262016-08-19 15:54:22 +03002743void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2744 FloatTypeUnaryFunc builtinFunc,
2745 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302746{
2747 ASSERT(builtinFunc);
2748
Olli Etuahof119a262016-08-19 15:54:22 +03002749 ASSERT(getType().getBasicType() == EbtFloat);
2750 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302751}
2752
Jamie Madillb1a85f42014-08-19 15:23:24 -04002753// static
Olli Etuahof119a262016-08-19 15:54:22 +03002754TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2755 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302756{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002757 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002758 TIntermSequence *arguments = aggregate->getSequence();
2759 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2760 std::vector<const TConstantUnion *> unionArrays(argsCount);
2761 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002762 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302763 TBasicType basicType = EbtVoid;
2764 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002765 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302766 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002767 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2768 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302769
2770 if (i == 0)
2771 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002772 basicType = argConstant->getType().getBasicType();
2773 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302774 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002775 unionArrays[i] = argConstant->getConstantValue();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002776 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002777 if (objectSizes[i] > maxObjectSize)
2778 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302779 }
2780
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002781 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302782 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002783 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302784 if (objectSizes[i] != maxObjectSize)
2785 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2786 }
Arun Patole274f0702015-05-05 13:33:30 +05302787
Olli Etuahob43846e2015-06-02 18:18:57 +03002788 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002789
2790 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302791 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002792 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302793 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002794 ASSERT(basicType == EbtFloat);
2795 resultArray = new TConstantUnion[maxObjectSize];
2796 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302797 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002798 float y = unionArrays[0][i].getFConst();
2799 float x = unionArrays[1][i].getFConst();
2800 // Results are undefined if x and y are both 0.
2801 if (x == 0.0f && y == 0.0f)
2802 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2803 else
2804 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302805 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002806 break;
2807 }
Arun Patolebf790422015-05-18 17:53:04 +05302808
Olli Etuaho51182ab2017-01-22 00:12:29 +00002809 case EOpPow:
2810 {
2811 ASSERT(basicType == EbtFloat);
2812 resultArray = new TConstantUnion[maxObjectSize];
2813 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302814 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002815 float x = unionArrays[0][i].getFConst();
2816 float y = unionArrays[1][i].getFConst();
2817 // Results are undefined if x < 0.
2818 // Results are undefined if x = 0 and y <= 0.
2819 if (x < 0.0f)
2820 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2821 else if (x == 0.0f && y <= 0.0f)
2822 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2823 else
2824 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302825 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002826 break;
2827 }
Arun Patolebf790422015-05-18 17:53:04 +05302828
Olli Etuaho51182ab2017-01-22 00:12:29 +00002829 case EOpMod:
2830 {
2831 ASSERT(basicType == EbtFloat);
2832 resultArray = new TConstantUnion[maxObjectSize];
2833 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302834 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002835 float x = unionArrays[0][i].getFConst();
2836 float y = unionArrays[1][i].getFConst();
2837 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302838 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002839 break;
2840 }
Arun Patolebf790422015-05-18 17:53:04 +05302841
Olli Etuaho51182ab2017-01-22 00:12:29 +00002842 case EOpMin:
2843 {
2844 resultArray = new TConstantUnion[maxObjectSize];
2845 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302846 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002847 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302848 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002849 case EbtFloat:
2850 resultArray[i].setFConst(
2851 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2852 break;
2853 case EbtInt:
2854 resultArray[i].setIConst(
2855 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2856 break;
2857 case EbtUInt:
2858 resultArray[i].setUConst(
2859 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2860 break;
2861 default:
2862 UNREACHABLE();
2863 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302864 }
2865 }
2866 break;
Arun Patole274f0702015-05-05 13:33:30 +05302867 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002868
2869 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302870 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002871 resultArray = new TConstantUnion[maxObjectSize];
2872 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302873 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002874 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302875 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002876 case EbtFloat:
2877 resultArray[i].setFConst(
2878 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2879 break;
2880 case EbtInt:
2881 resultArray[i].setIConst(
2882 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2883 break;
2884 case EbtUInt:
2885 resultArray[i].setUConst(
2886 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2887 break;
2888 default:
2889 UNREACHABLE();
2890 break;
Arun Patole274f0702015-05-05 13:33:30 +05302891 }
2892 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002893 break;
Arun Patole274f0702015-05-05 13:33:30 +05302894 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002895
2896 case EOpStep:
2897 {
2898 ASSERT(basicType == EbtFloat);
2899 resultArray = new TConstantUnion[maxObjectSize];
2900 for (size_t i = 0; i < maxObjectSize; i++)
2901 resultArray[i].setFConst(
2902 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2903 break;
2904 }
2905
2906 case EOpLessThanComponentWise:
2907 {
2908 resultArray = new TConstantUnion[maxObjectSize];
2909 for (size_t i = 0; i < maxObjectSize; i++)
2910 {
2911 switch (basicType)
2912 {
2913 case EbtFloat:
2914 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2915 unionArrays[1][i].getFConst());
2916 break;
2917 case EbtInt:
2918 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2919 unionArrays[1][i].getIConst());
2920 break;
2921 case EbtUInt:
2922 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2923 unionArrays[1][i].getUConst());
2924 break;
2925 default:
2926 UNREACHABLE();
2927 break;
2928 }
2929 }
2930 break;
2931 }
2932
2933 case EOpLessThanEqualComponentWise:
2934 {
2935 resultArray = new TConstantUnion[maxObjectSize];
2936 for (size_t i = 0; i < maxObjectSize; i++)
2937 {
2938 switch (basicType)
2939 {
2940 case EbtFloat:
2941 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2942 unionArrays[1][i].getFConst());
2943 break;
2944 case EbtInt:
2945 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2946 unionArrays[1][i].getIConst());
2947 break;
2948 case EbtUInt:
2949 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2950 unionArrays[1][i].getUConst());
2951 break;
2952 default:
2953 UNREACHABLE();
2954 break;
2955 }
2956 }
2957 break;
2958 }
2959
2960 case EOpGreaterThanComponentWise:
2961 {
2962 resultArray = new TConstantUnion[maxObjectSize];
2963 for (size_t i = 0; i < maxObjectSize; i++)
2964 {
2965 switch (basicType)
2966 {
2967 case EbtFloat:
2968 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2969 unionArrays[1][i].getFConst());
2970 break;
2971 case EbtInt:
2972 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2973 unionArrays[1][i].getIConst());
2974 break;
2975 case EbtUInt:
2976 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2977 unionArrays[1][i].getUConst());
2978 break;
2979 default:
2980 UNREACHABLE();
2981 break;
2982 }
2983 }
2984 break;
2985 }
2986 case EOpGreaterThanEqualComponentWise:
2987 {
2988 resultArray = new TConstantUnion[maxObjectSize];
2989 for (size_t i = 0; i < maxObjectSize; i++)
2990 {
2991 switch (basicType)
2992 {
2993 case EbtFloat:
2994 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2995 unionArrays[1][i].getFConst());
2996 break;
2997 case EbtInt:
2998 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2999 unionArrays[1][i].getIConst());
3000 break;
3001 case EbtUInt:
3002 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
3003 unionArrays[1][i].getUConst());
3004 break;
3005 default:
3006 UNREACHABLE();
3007 break;
3008 }
3009 }
3010 }
3011 break;
3012
3013 case EOpEqualComponentWise:
3014 {
3015 resultArray = new TConstantUnion[maxObjectSize];
3016 for (size_t i = 0; i < maxObjectSize; i++)
3017 {
3018 switch (basicType)
3019 {
3020 case EbtFloat:
3021 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
3022 unionArrays[1][i].getFConst());
3023 break;
3024 case EbtInt:
3025 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
3026 unionArrays[1][i].getIConst());
3027 break;
3028 case EbtUInt:
3029 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
3030 unionArrays[1][i].getUConst());
3031 break;
3032 case EbtBool:
3033 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
3034 unionArrays[1][i].getBConst());
3035 break;
3036 default:
3037 UNREACHABLE();
3038 break;
3039 }
3040 }
3041 break;
3042 }
3043
3044 case EOpNotEqualComponentWise:
3045 {
3046 resultArray = new TConstantUnion[maxObjectSize];
3047 for (size_t i = 0; i < maxObjectSize; i++)
3048 {
3049 switch (basicType)
3050 {
3051 case EbtFloat:
3052 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
3053 unionArrays[1][i].getFConst());
3054 break;
3055 case EbtInt:
3056 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3057 unionArrays[1][i].getIConst());
3058 break;
3059 case EbtUInt:
3060 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3061 unionArrays[1][i].getUConst());
3062 break;
3063 case EbtBool:
3064 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3065 unionArrays[1][i].getBConst());
3066 break;
3067 default:
3068 UNREACHABLE();
3069 break;
3070 }
3071 }
3072 break;
3073 }
3074
3075 case EOpDistance:
3076 {
3077 ASSERT(basicType == EbtFloat);
3078 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3079 resultArray = new TConstantUnion();
3080 for (size_t i = 0; i < maxObjectSize; i++)
3081 {
3082 float x = unionArrays[0][i].getFConst();
3083 float y = unionArrays[1][i].getFConst();
3084 distanceArray[i].setFConst(x - y);
3085 }
3086 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3087 break;
3088 }
3089
3090 case EOpDot:
3091 ASSERT(basicType == EbtFloat);
3092 resultArray = new TConstantUnion();
3093 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3094 break;
3095
3096 case EOpCross:
3097 {
3098 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3099 resultArray = new TConstantUnion[maxObjectSize];
3100 float x0 = unionArrays[0][0].getFConst();
3101 float x1 = unionArrays[0][1].getFConst();
3102 float x2 = unionArrays[0][2].getFConst();
3103 float y0 = unionArrays[1][0].getFConst();
3104 float y1 = unionArrays[1][1].getFConst();
3105 float y2 = unionArrays[1][2].getFConst();
3106 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3107 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3108 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3109 break;
3110 }
3111
3112 case EOpReflect:
3113 {
3114 ASSERT(basicType == EbtFloat);
3115 // genType reflect (genType I, genType N) :
3116 // For the incident vector I and surface orientation N, returns the reflection
3117 // direction:
3118 // I - 2 * dot(N, I) * N.
3119 resultArray = new TConstantUnion[maxObjectSize];
3120 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3121 for (size_t i = 0; i < maxObjectSize; i++)
3122 {
3123 float result = unionArrays[0][i].getFConst() -
3124 2.0f * dotProduct * unionArrays[1][i].getFConst();
3125 resultArray[i].setFConst(result);
3126 }
3127 break;
3128 }
3129
3130 case EOpMulMatrixComponentWise:
3131 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003132 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3133 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003134 // Perform component-wise matrix multiplication.
3135 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003136 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003137 angle::Matrix<float> result =
3138 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3139 SetUnionArrayFromMatrix(result, resultArray);
3140 break;
3141 }
3142
3143 case EOpOuterProduct:
3144 {
3145 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003146 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3147 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003148 resultArray = new TConstantUnion[numRows * numCols];
3149 angle::Matrix<float> result =
3150 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3151 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3152 SetUnionArrayFromMatrix(result, resultArray);
3153 break;
3154 }
3155
3156 case EOpClamp:
3157 {
3158 resultArray = new TConstantUnion[maxObjectSize];
3159 for (size_t i = 0; i < maxObjectSize; i++)
3160 {
3161 switch (basicType)
3162 {
3163 case EbtFloat:
3164 {
3165 float x = unionArrays[0][i].getFConst();
3166 float min = unionArrays[1][i].getFConst();
3167 float max = unionArrays[2][i].getFConst();
3168 // Results are undefined if min > max.
3169 if (min > max)
3170 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3171 &resultArray[i]);
3172 else
3173 resultArray[i].setFConst(gl::clamp(x, min, max));
3174 break;
3175 }
3176
3177 case EbtInt:
3178 {
3179 int x = unionArrays[0][i].getIConst();
3180 int min = unionArrays[1][i].getIConst();
3181 int max = unionArrays[2][i].getIConst();
3182 // Results are undefined if min > max.
3183 if (min > max)
3184 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3185 &resultArray[i]);
3186 else
3187 resultArray[i].setIConst(gl::clamp(x, min, max));
3188 break;
3189 }
3190 case EbtUInt:
3191 {
3192 unsigned int x = unionArrays[0][i].getUConst();
3193 unsigned int min = unionArrays[1][i].getUConst();
3194 unsigned int max = unionArrays[2][i].getUConst();
3195 // Results are undefined if min > max.
3196 if (min > max)
3197 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3198 &resultArray[i]);
3199 else
3200 resultArray[i].setUConst(gl::clamp(x, min, max));
3201 break;
3202 }
3203 default:
3204 UNREACHABLE();
3205 break;
3206 }
3207 }
3208 break;
3209 }
3210
3211 case EOpMix:
3212 {
3213 ASSERT(basicType == EbtFloat);
3214 resultArray = new TConstantUnion[maxObjectSize];
3215 for (size_t i = 0; i < maxObjectSize; i++)
3216 {
3217 float x = unionArrays[0][i].getFConst();
3218 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003219 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003220 if (type == EbtFloat)
3221 {
3222 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3223 float a = unionArrays[2][i].getFConst();
3224 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3225 }
3226 else // 3rd parameter is EbtBool
3227 {
3228 ASSERT(type == EbtBool);
3229 // Selects which vector each returned component comes from.
3230 // For a component of a that is false, the corresponding component of x is
3231 // returned.
3232 // For a component of a that is true, the corresponding component of y is
3233 // returned.
3234 bool a = unionArrays[2][i].getBConst();
3235 resultArray[i].setFConst(a ? y : x);
3236 }
3237 }
3238 break;
3239 }
3240
3241 case EOpSmoothStep:
3242 {
3243 ASSERT(basicType == EbtFloat);
3244 resultArray = new TConstantUnion[maxObjectSize];
3245 for (size_t i = 0; i < maxObjectSize; i++)
3246 {
3247 float edge0 = unionArrays[0][i].getFConst();
3248 float edge1 = unionArrays[1][i].getFConst();
3249 float x = unionArrays[2][i].getFConst();
3250 // Results are undefined if edge0 >= edge1.
3251 if (edge0 >= edge1)
3252 {
3253 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3254 }
3255 else
3256 {
3257 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3258 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3259 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3260 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3261 }
3262 }
3263 break;
3264 }
3265
Olli Etuaho74da73f2017-02-01 15:37:48 +00003266 case EOpLdexp:
3267 {
3268 resultArray = new TConstantUnion[maxObjectSize];
3269 for (size_t i = 0; i < maxObjectSize; i++)
3270 {
3271 float x = unionArrays[0][i].getFConst();
3272 int exp = unionArrays[1][i].getIConst();
3273 if (exp > 128)
3274 {
3275 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3276 }
3277 else
3278 {
3279 resultArray[i].setFConst(gl::Ldexp(x, exp));
3280 }
3281 }
3282 break;
3283 }
3284
Jamie Madille72595b2017-06-06 15:12:26 -04003285 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003286 {
3287 ASSERT(basicType == EbtFloat);
3288 // genType faceforward(genType N, genType I, genType Nref) :
3289 // If dot(Nref, I) < 0 return N, otherwise return -N.
3290 resultArray = new TConstantUnion[maxObjectSize];
3291 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3292 for (size_t i = 0; i < maxObjectSize; i++)
3293 {
3294 if (dotProduct < 0)
3295 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3296 else
3297 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3298 }
3299 break;
3300 }
3301
3302 case EOpRefract:
3303 {
3304 ASSERT(basicType == EbtFloat);
3305 // genType refract(genType I, genType N, float eta) :
3306 // For the incident vector I and surface normal N, and the ratio of indices of
3307 // refraction eta,
3308 // return the refraction vector. The result is computed by
3309 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3310 // if (k < 0.0)
3311 // return genType(0.0)
3312 // else
3313 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3314 resultArray = new TConstantUnion[maxObjectSize];
3315 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3316 for (size_t i = 0; i < maxObjectSize; i++)
3317 {
3318 float eta = unionArrays[2][i].getFConst();
3319 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3320 if (k < 0.0f)
3321 resultArray[i].setFConst(0.0f);
3322 else
3323 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3324 (eta * dotProduct + sqrtf(k)) *
3325 unionArrays[1][i].getFConst());
3326 }
3327 break;
3328 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003329 case EOpBitfieldExtract:
3330 {
3331 resultArray = new TConstantUnion[maxObjectSize];
3332 for (size_t i = 0; i < maxObjectSize; ++i)
3333 {
3334 int offset = unionArrays[1][0].getIConst();
3335 int bits = unionArrays[2][0].getIConst();
3336 if (bits == 0)
3337 {
3338 if (aggregate->getBasicType() == EbtInt)
3339 {
3340 resultArray[i].setIConst(0);
3341 }
3342 else
3343 {
3344 ASSERT(aggregate->getBasicType() == EbtUInt);
3345 resultArray[i].setUConst(0);
3346 }
3347 }
3348 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3349 {
3350 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3351 &resultArray[i]);
3352 }
3353 else
3354 {
3355 // bits can be 32 here, so we need to avoid bit shift overflow.
3356 uint32_t maskMsb = 1u << (bits - 1);
3357 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3358 if (aggregate->getBasicType() == EbtInt)
3359 {
3360 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3361 uint32_t resultUnsigned = (value & mask) >> offset;
3362 if ((resultUnsigned & maskMsb) != 0)
3363 {
3364 // The most significant bits (from bits+1 to the most significant bit)
3365 // should be set to 1.
3366 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3367 resultUnsigned |= higherBitsMask;
3368 }
3369 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3370 }
3371 else
3372 {
3373 ASSERT(aggregate->getBasicType() == EbtUInt);
3374 uint32_t value = unionArrays[0][i].getUConst();
3375 resultArray[i].setUConst((value & mask) >> offset);
3376 }
3377 }
3378 }
3379 break;
3380 }
3381 case EOpBitfieldInsert:
3382 {
3383 resultArray = new TConstantUnion[maxObjectSize];
3384 for (size_t i = 0; i < maxObjectSize; ++i)
3385 {
3386 int offset = unionArrays[2][0].getIConst();
3387 int bits = unionArrays[3][0].getIConst();
3388 if (bits == 0)
3389 {
3390 if (aggregate->getBasicType() == EbtInt)
3391 {
3392 int32_t base = unionArrays[0][i].getIConst();
3393 resultArray[i].setIConst(base);
3394 }
3395 else
3396 {
3397 ASSERT(aggregate->getBasicType() == EbtUInt);
3398 uint32_t base = unionArrays[0][i].getUConst();
3399 resultArray[i].setUConst(base);
3400 }
3401 }
3402 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3403 {
3404 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3405 &resultArray[i]);
3406 }
3407 else
3408 {
3409 // bits can be 32 here, so we need to avoid bit shift overflow.
3410 uint32_t maskMsb = 1u << (bits - 1);
3411 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3412 uint32_t baseMask = ~insertMask;
3413 if (aggregate->getBasicType() == EbtInt)
3414 {
3415 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3416 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3417 uint32_t resultUnsigned =
3418 (base & baseMask) | ((insert << offset) & insertMask);
3419 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3420 }
3421 else
3422 {
3423 ASSERT(aggregate->getBasicType() == EbtUInt);
3424 uint32_t base = unionArrays[0][i].getUConst();
3425 uint32_t insert = unionArrays[1][i].getUConst();
3426 resultArray[i].setUConst((base & baseMask) |
3427 ((insert << offset) & insertMask));
3428 }
3429 }
3430 }
3431 break;
3432 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003433
3434 default:
3435 UNREACHABLE();
3436 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303437 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003438 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303439}
3440
Jamie Madill45bcc782016-11-07 13:58:48 -05003441} // namespace sh