blob: c40a093523cddb34d786717f1712d0de9ebb0070 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Olli Etuahofbb1c792018-01-19 16:26:59 +020021#include "compiler/translator/ImmutableString.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040022#include "compiler/translator/IntermNode.h"
23#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040024#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040025
Jamie Madill45bcc782016-11-07 13:58:48 -050026namespace sh
27{
28
Jamie Madillb1a85f42014-08-19 15:23:24 -040029namespace
30{
31
Jamie Madilld7b1ab52016-12-12 14:42:19 -050032const float kPi = 3.14159265358979323846f;
Arun Patole9dea48f2015-04-02 11:45:09 +053033const float kDegreesToRadiansMultiplier = kPi / 180.0f;
34const float kRadiansToDegreesMultiplier = 180.0f / kPi;
35
Jamie Madillb1a85f42014-08-19 15:23:24 -040036TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
37{
38 return left > right ? left : right;
39}
40
Arun Patole274f0702015-05-05 13:33:30 +053041TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
42{
43 TConstantUnion *constUnion = new TConstantUnion[size];
44 for (unsigned int i = 0; i < size; ++i)
Jamie Madilld7b1ab52016-12-12 14:42:19 -050045 constUnion[i] = constant;
Arun Patole274f0702015-05-05 13:33:30 +053046
47 return constUnion;
48}
49
Olli Etuahof119a262016-08-19 15:54:22 +030050void UndefinedConstantFoldingError(const TSourceLoc &loc,
51 TOperator op,
52 TBasicType basicType,
53 TDiagnostics *diagnostics,
54 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053055{
Olli Etuahof119a262016-08-19 15:54:22 +030056 diagnostics->warning(loc, "operation result is undefined for the values passed in",
Olli Etuaho4de340a2016-12-16 09:32:03 +000057 GetOperatorString(op));
Arun Patolebf790422015-05-18 17:53:04 +053058
59 switch (basicType)
60 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050061 case EbtFloat:
62 result->setFConst(0.0f);
63 break;
64 case EbtInt:
65 result->setIConst(0);
66 break;
67 case EbtUInt:
68 result->setUConst(0u);
69 break;
70 case EbtBool:
71 result->setBConst(false);
72 break;
73 default:
74 break;
Arun Patolebf790422015-05-18 17:53:04 +053075 }
76}
77
Olli Etuaho5c0e0232015-11-11 15:55:59 +020078float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053079{
80 float result = 0.0f;
81 for (size_t i = 0; i < paramArraySize; i++)
82 {
83 float f = paramArray[i].getFConst();
84 result += f * f;
85 }
86 return sqrtf(result);
87}
88
Olli Etuaho5c0e0232015-11-11 15:55:59 +020089float VectorDotProduct(const TConstantUnion *paramArray1,
90 const TConstantUnion *paramArray2,
91 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053092{
93 float result = 0.0f;
94 for (size_t i = 0; i < paramArraySize; i++)
95 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
96 return result;
97}
98
Olli Etuaho2768bc82017-12-12 11:51:48 +020099TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray, const TIntermTyped *originalNode)
Olli Etuahob43846e2015-06-02 18:18:57 +0300100{
Olli Etuaho2768bc82017-12-12 11:51:48 +0200101 ASSERT(constArray != nullptr);
102 // Note that we inherit whatever qualifier the folded node had. Nodes may be constant folded
103 // without being qualified as constant.
Olli Etuahob43846e2015-06-02 18:18:57 +0300104 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuahob43846e2015-06-02 18:18:57 +0300105 folded->setLine(originalNode->getLine());
106 return folded;
107}
108
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200109angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
110 const unsigned int &rows,
111 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530112{
113 std::vector<float> elements;
114 for (size_t i = 0; i < rows * cols; i++)
115 elements.push_back(paramArray[i].getFConst());
116 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300117 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
118 // so that the created matrix will have the expected dimensions after the transpose.
119 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530120}
121
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200122angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530123{
124 std::vector<float> elements;
125 for (size_t i = 0; i < size * size; i++)
126 elements.push_back(paramArray[i].getFConst());
127 // Transpose is used since the Matrix constructor expects arguments in row-major order,
128 // whereas the paramArray is in column-major order.
129 return angle::Matrix<float>(elements, size).transpose();
130}
131
132void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
133{
134 // Transpose is used since the input Matrix is in row-major order,
135 // whereas the actual result should be in column-major order.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500136 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530137 std::vector<float> resultElements = result.elements();
138 for (size_t i = 0; i < resultElements.size(); i++)
139 resultArray[i].setFConst(resultElements[i]);
140}
141
Olli Etuaho765924f2018-01-04 12:48:36 +0200142bool CanFoldAggregateBuiltInOp(TOperator op)
143{
144 switch (op)
145 {
146 case EOpAtan:
147 case EOpPow:
148 case EOpMod:
149 case EOpMin:
150 case EOpMax:
151 case EOpClamp:
152 case EOpMix:
153 case EOpStep:
154 case EOpSmoothStep:
155 case EOpLdexp:
156 case EOpMulMatrixComponentWise:
157 case EOpOuterProduct:
158 case EOpEqualComponentWise:
159 case EOpNotEqualComponentWise:
160 case EOpLessThanComponentWise:
161 case EOpLessThanEqualComponentWise:
162 case EOpGreaterThanComponentWise:
163 case EOpGreaterThanEqualComponentWise:
164 case EOpDistance:
165 case EOpDot:
166 case EOpCross:
167 case EOpFaceforward:
168 case EOpReflect:
169 case EOpRefract:
170 case EOpBitfieldExtract:
171 case EOpBitfieldInsert:
172 return true;
173 default:
174 return false;
175 }
176}
177
Jamie Madillb1a85f42014-08-19 15:23:24 -0400178} // namespace anonymous
179
Jamie Madillb1a85f42014-08-19 15:23:24 -0400180////////////////////////////////////////////////////////////////
181//
182// Member functions of the nodes used for building the tree.
183//
184////////////////////////////////////////////////////////////////
185
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200186TIntermExpression::TIntermExpression(const TType &t) : TIntermTyped(), mType(t)
187{
188}
189
190void TIntermExpression::setTypePreservePrecision(const TType &t)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300191{
192 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500193 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300194 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
195 mType.setPrecision(precision);
196}
197
Jamie Madillb1a85f42014-08-19 15:23:24 -0400198#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500199 if (node == original) \
200 { \
201 node = static_cast<type *>(replacement); \
202 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400203 }
204
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500205bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400206{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300207 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400208 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
209 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
210 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100211 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400212 return false;
213}
214
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500215bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400216{
217 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
218 return false;
219}
220
Olli Etuahob6fa0432016-09-28 16:28:05 +0100221bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
222{
223 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
224 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
225 return false;
226}
227
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500228bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400229{
230 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
231 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
232 return false;
233}
234
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500235bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400236{
Olli Etuahoa2234302016-08-31 12:05:39 +0300237 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400238 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
239 return false;
240}
241
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000242bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
243{
244 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
245 return false;
246}
247
Olli Etuaho336b1472016-10-05 16:37:55 +0100248bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
249{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000250 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100251 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
252 return false;
253}
254
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500255bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400256{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100257 return replaceChildNodeInternal(original, replacement);
258}
259
260bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
261{
262 return replaceChildNodeInternal(original, replacement);
263}
264
Olli Etuaho16c745a2017-01-16 17:02:27 +0000265bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
266{
267 return replaceChildNodeInternal(original, replacement);
268}
269
Olli Etuaho13389b62016-10-16 11:48:18 +0100270bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
271{
272 return replaceChildNodeInternal(original, replacement);
273}
274
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100275bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
276{
277 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400278 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100279 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400280 }
281 return false;
282}
283
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100284bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
285 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300286{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100287 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300288 {
289 if (*it == original)
290 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100291 it = getSequence()->erase(it);
292 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300293 return true;
294 }
295 }
296 return false;
297}
298
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100299bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
300 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300301{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100302 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300303 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300304 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300305 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100306 auto it = getSequence()->begin() + position;
307 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300308 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300309}
310
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200311TIntermSymbol::TIntermSymbol(const TVariable *variable) : TIntermTyped(), mVariable(variable)
Olli Etuaho195be942017-12-04 23:40:14 +0200312{
Olli Etuaho195be942017-12-04 23:40:14 +0200313}
314
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200315bool TIntermSymbol::hasConstantValue() const
316{
317 return variable().getConstPointer() != nullptr;
318}
319
320const TConstantUnion *TIntermSymbol::getConstantValue() const
321{
322 return variable().getConstPointer();
323}
324
Olli Etuahob6af22b2017-12-15 14:05:44 +0200325const TSymbolUniqueId &TIntermSymbol::uniqueId() const
326{
327 return mVariable->uniqueId();
328}
329
Olli Etuahofbb1c792018-01-19 16:26:59 +0200330ImmutableString TIntermSymbol::getName() const
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200331{
332 return mVariable->name();
333}
334
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200335const TType &TIntermSymbol::getType() const
336{
337 return mVariable->getType();
338}
339
Olli Etuahofe486322017-03-21 09:30:54 +0000340TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
341 TIntermSequence *arguments)
342{
Olli Etuaho0c371002017-12-13 17:00:25 +0400343 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000344}
345
Olli Etuaho0c371002017-12-13 17:00:25 +0400346TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
347 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000348{
Olli Etuaho0c371002017-12-13 17:00:25 +0400349 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000350}
351
352TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
353 TIntermSequence *arguments)
354{
355 TIntermAggregate *callNode =
Olli Etuaho0c371002017-12-13 17:00:25 +0400356 new TIntermAggregate(&func, func.getReturnType(), EOpCallBuiltInFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000357 // Note that name needs to be set before texture function type is determined.
358 callNode->setBuiltInFunctionPrecision();
359 return callNode;
360}
361
362TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000363 TIntermSequence *arguments)
364{
Olli Etuaho0c371002017-12-13 17:00:25 +0400365 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000366}
367
Olli Etuaho68981eb2018-01-23 17:46:12 +0200368TIntermAggregate *TIntermAggregate::Create(const TFunction &func,
Olli Etuahofe486322017-03-21 09:30:54 +0000369 TOperator op,
370 TIntermSequence *arguments)
371{
Olli Etuahofe486322017-03-21 09:30:54 +0000372 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400373 ASSERT(op != EOpCallInternalRawFunction); // Should use CreateRawFunctionCall
Olli Etuahofe486322017-03-21 09:30:54 +0000374 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400375 ASSERT(op != EOpConstruct); // Should use CreateConstructor
Olli Etuaho68981eb2018-01-23 17:46:12 +0200376 return new TIntermAggregate(&func, func.getReturnType(), op, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000377}
378
Olli Etuaho0c371002017-12-13 17:00:25 +0400379TIntermAggregate::TIntermAggregate(const TFunction *func,
380 const TType &type,
381 TOperator op,
382 TIntermSequence *arguments)
383 : TIntermOperator(op),
384 mUseEmulatedFunction(false),
385 mGotPrecisionFromChildren(false),
386 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800387{
388 if (arguments != nullptr)
389 {
390 mArguments.swap(*arguments);
391 }
Olli Etuaho1bb85282017-12-14 13:39:53 +0200392 ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800393 setTypePrecisionAndQualifier(type);
394}
395
396void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
397{
398 setType(type);
399 mType.setQualifier(EvqTemporary);
400 if (!isFunctionCall())
401 {
402 if (isConstructor())
403 {
404 // Structs should not be precision qualified, the individual members may be.
405 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300406 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800407 {
408 setPrecisionFromChildren();
409 }
410 }
411 else
412 {
413 setPrecisionForBuiltInOp();
414 }
415 if (areChildrenConstQualified())
416 {
417 mType.setQualifier(EvqConst);
418 }
419 }
420}
421
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200422bool TIntermAggregate::areChildrenConstQualified()
423{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800424 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200425 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800426 TIntermTyped *typedArg = arg->getAsTyped();
427 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200428 {
429 return false;
430 }
431 }
432 return true;
433}
434
Olli Etuahod2a67b92014-10-21 16:42:57 +0300435void TIntermAggregate::setPrecisionFromChildren()
436{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300437 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300438 if (getBasicType() == EbtBool)
439 {
440 mType.setPrecision(EbpUndefined);
441 return;
442 }
443
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500444 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800445 TIntermSequence::iterator childIter = mArguments.begin();
446 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300447 {
448 TIntermTyped *typed = (*childIter)->getAsTyped();
449 if (typed)
450 precision = GetHigherPrecision(typed->getPrecision(), precision);
451 ++childIter;
452 }
453 mType.setPrecision(precision);
454}
455
Olli Etuaho9250cb22017-01-21 10:51:27 +0000456void TIntermAggregate::setPrecisionForBuiltInOp()
457{
458 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800459 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000460 if (!setPrecisionForSpecialBuiltInOp())
461 {
462 setPrecisionFromChildren();
463 }
464}
465
466bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
467{
468 switch (mOp)
469 {
470 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800471 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
472 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000473 return true;
474 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800475 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
476 mArguments[1]->getAsTyped()->getPrecision()));
477 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000478 return true;
479 case EOpUaddCarry:
480 case EOpUsubBorrow:
481 mType.setPrecision(EbpHigh);
482 return true;
483 default:
484 return false;
485 }
486}
487
Olli Etuahod2a67b92014-10-21 16:42:57 +0300488void TIntermAggregate::setBuiltInFunctionPrecision()
489{
490 // All built-ins returning bool should be handled as ops, not functions.
491 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800492 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300493
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800494 TPrecision precision = EbpUndefined;
495 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300496 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800497 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300498 // ESSL spec section 8: texture functions get their precision from the sampler.
499 if (typed && IsSampler(typed->getBasicType()))
500 {
501 precision = typed->getPrecision();
502 break;
503 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300504 }
505 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
506 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahofbb1c792018-01-19 16:26:59 +0200507 if (mFunction->name() == "textureSize")
Olli Etuahod2a67b92014-10-21 16:42:57 +0300508 mType.setPrecision(EbpHigh);
509 else
510 mType.setPrecision(precision);
511}
512
Olli Etuaho0c371002017-12-13 17:00:25 +0400513const char *TIntermAggregate::functionName() const
514{
515 ASSERT(!isConstructor());
516 switch (mOp)
517 {
518 case EOpCallInternalRawFunction:
519 case EOpCallBuiltInFunction:
520 case EOpCallFunctionInAST:
Olli Etuahofbb1c792018-01-19 16:26:59 +0200521 return mFunction->name().data();
Olli Etuaho0c371002017-12-13 17:00:25 +0400522 default:
523 return GetOperatorString(mOp);
524 }
525}
526
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200527bool TIntermAggregate::hasConstantValue() const
528{
529 if (!isConstructor())
530 {
531 return false;
532 }
533 for (TIntermNode *constructorArg : mArguments)
534 {
535 if (!constructorArg->getAsTyped()->hasConstantValue())
536 {
537 return false;
538 }
539 }
540 return true;
541}
542
543const TConstantUnion *TIntermAggregate::getConstantValue() const
544{
545 if (!hasConstantValue())
546 {
547 return nullptr;
548 }
549 ASSERT(isConstructor());
550 ASSERT(mArguments.size() > 0u);
551
552 TConstantUnion *constArray = nullptr;
553 if (isArray())
554 {
555 size_t elementSize = mArguments.front()->getAsTyped()->getType().getObjectSize();
556 constArray = new TConstantUnion[elementSize * getOutermostArraySize()];
557
558 size_t elementOffset = 0u;
559 for (TIntermNode *constructorArg : mArguments)
560 {
561 const TConstantUnion *elementConstArray =
562 constructorArg->getAsTyped()->getConstantValue();
563 ASSERT(elementConstArray);
564 size_t elementSizeBytes = sizeof(TConstantUnion) * elementSize;
565 memcpy(static_cast<void *>(&constArray[elementOffset]),
566 static_cast<const void *>(elementConstArray), elementSizeBytes);
567 elementOffset += elementSize;
568 }
569 return constArray;
570 }
571
572 size_t resultSize = getType().getObjectSize();
573 constArray = new TConstantUnion[resultSize];
574 TBasicType basicType = getBasicType();
575
576 size_t resultIndex = 0u;
577
578 if (mArguments.size() == 1u)
579 {
580 TIntermNode *argument = mArguments.front();
581 TIntermTyped *argumentTyped = argument->getAsTyped();
582 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
583 // Check the special case of constructing a matrix diagonal from a single scalar,
584 // or a vector from a single scalar.
585 if (argumentTyped->getType().getObjectSize() == 1u)
586 {
587 if (isMatrix())
588 {
589 int resultCols = getType().getCols();
590 int resultRows = getType().getRows();
591 for (int col = 0; col < resultCols; ++col)
592 {
593 for (int row = 0; row < resultRows; ++row)
594 {
595 if (col == row)
596 {
597 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
598 }
599 else
600 {
601 constArray[resultIndex].setFConst(0.0f);
602 }
603 ++resultIndex;
604 }
605 }
606 }
607 else
608 {
609 while (resultIndex < resultSize)
610 {
611 constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
612 ++resultIndex;
613 }
614 }
615 ASSERT(resultIndex == resultSize);
616 return constArray;
617 }
618 else if (isMatrix() && argumentTyped->isMatrix())
619 {
620 // The special case of constructing a matrix from a matrix.
621 int argumentCols = argumentTyped->getType().getCols();
622 int argumentRows = argumentTyped->getType().getRows();
623 int resultCols = getType().getCols();
624 int resultRows = getType().getRows();
625 for (int col = 0; col < resultCols; ++col)
626 {
627 for (int row = 0; row < resultRows; ++row)
628 {
629 if (col < argumentCols && row < argumentRows)
630 {
631 constArray[resultIndex].cast(
632 basicType, argumentConstantValue[col * argumentRows + row]);
633 }
634 else if (col == row)
635 {
636 constArray[resultIndex].setFConst(1.0f);
637 }
638 else
639 {
640 constArray[resultIndex].setFConst(0.0f);
641 }
642 ++resultIndex;
643 }
644 }
645 ASSERT(resultIndex == resultSize);
646 return constArray;
647 }
648 }
649
650 for (TIntermNode *argument : mArguments)
651 {
652 TIntermTyped *argumentTyped = argument->getAsTyped();
653 size_t argumentSize = argumentTyped->getType().getObjectSize();
654 const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
655 for (size_t i = 0u; i < argumentSize; ++i)
656 {
657 if (resultIndex >= resultSize)
658 break;
659 constArray[resultIndex].cast(basicType, argumentConstantValue[i]);
660 ++resultIndex;
661 }
662 }
663 ASSERT(resultIndex == resultSize);
664 return constArray;
665}
666
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300667bool TIntermAggregate::hasSideEffects() const
668{
Olli Etuahoea78d2b2018-01-09 12:55:27 +0200669 if (getQualifier() == EvqConst)
670 {
671 return false;
672 }
673 bool calledFunctionHasNoSideEffects =
674 isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects();
675 if (calledFunctionHasNoSideEffects || isConstructor())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300676 {
677 for (TIntermNode *arg : mArguments)
678 {
679 if (arg->getAsTyped()->hasSideEffects())
680 {
681 return true;
682 }
683 }
684 return false;
685 }
686 // Conservatively assume most aggregate operators have side-effects
687 return true;
688}
689
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100690void TIntermBlock::appendStatement(TIntermNode *statement)
691{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300692 // Declaration nodes with no children can appear if it was an empty declaration or if all the
693 // declarators just added constants to the symbol table instead of generating code. We still
694 // need to add the declaration to the AST in that case because it might be relevant to the
695 // validity of switch/case.
696 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100697 {
698 mStatements.push_back(statement);
699 }
700}
701
Olli Etuaho16c745a2017-01-16 17:02:27 +0000702void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
703{
704 ASSERT(parameter != nullptr);
705 mParameters.push_back(parameter);
706}
707
Olli Etuaho13389b62016-10-16 11:48:18 +0100708void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
709{
710 ASSERT(declarator != nullptr);
711 ASSERT(declarator->getAsSymbolNode() != nullptr ||
712 (declarator->getAsBinaryNode() != nullptr &&
713 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
714 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300715 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100716 mDeclarators.push_back(declarator);
717}
718
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300719bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
720{
721 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
722 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
723 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
724 return false;
725}
726
Olli Etuaho57961272016-09-14 13:57:46 +0300727bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400728{
729 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100730 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
731 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400732 return false;
733}
734
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500735bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200736{
737 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100738 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300739 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200740 return false;
741}
742
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500743bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200744{
745 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
746 return false;
747}
748
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200749TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode()
Olli Etuahod7a25242015-08-18 13:49:45 +0300750{
751 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
752 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200753 // We need to manually copy any fields of TIntermNode.
Olli Etuahod7a25242015-08-18 13:49:45 +0300754 mLine = node.mLine;
755}
756
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200757bool TIntermTyped::hasConstantValue() const
Olli Etuahod4f4c112016-04-15 15:11:24 +0300758{
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200759 return false;
760}
761
762const TConstantUnion *TIntermTyped::getConstantValue() const
763{
764 return nullptr;
Olli Etuahod4f4c112016-04-15 15:11:24 +0300765}
766
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200767TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node)
768 : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300769{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200770 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300771}
772
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200773TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200774 : TIntermTyped(), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100775{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200776 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100777}
778
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200779const TType &TIntermFunctionPrototype::getType() const
780{
781 return mFunction->getReturnType();
782}
783
Olli Etuahod7a25242015-08-18 13:49:45 +0300784TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
785 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300786 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100787 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400788 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300789{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800790 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300791 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800792 TIntermTyped *typedArg = arg->getAsTyped();
793 ASSERT(typedArg != nullptr);
794 TIntermTyped *argCopy = typedArg->deepCopy();
795 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300796 }
797}
798
Olli Etuahofe486322017-03-21 09:30:54 +0000799TIntermAggregate *TIntermAggregate::shallowCopy() const
800{
801 TIntermSequence *copySeq = new TIntermSequence();
802 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400803 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000804 copyNode->setLine(mLine);
805 return copyNode;
806}
807
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200808TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermExpression(node)
Olli Etuahob6fa0432016-09-28 16:28:05 +0100809{
810 TIntermTyped *operandCopy = node.mOperand->deepCopy();
811 ASSERT(operandCopy != nullptr);
812 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000813 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100814}
815
Olli Etuahod7a25242015-08-18 13:49:45 +0300816TIntermBinary::TIntermBinary(const TIntermBinary &node)
817 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
818{
819 TIntermTyped *leftCopy = node.mLeft->deepCopy();
820 TIntermTyped *rightCopy = node.mRight->deepCopy();
821 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
822 mLeft = leftCopy;
823 mRight = rightCopy;
824}
825
826TIntermUnary::TIntermUnary(const TIntermUnary &node)
827 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
828{
829 TIntermTyped *operandCopy = node.mOperand->deepCopy();
830 ASSERT(operandCopy != nullptr);
831 mOperand = operandCopy;
832}
833
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +0200834TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300835{
Olli Etuahod7a25242015-08-18 13:49:45 +0300836 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300837 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
838 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300839 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300840 mCondition = conditionCopy;
841 mTrueExpression = trueCopy;
842 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300843}
844
Jamie Madillb1a85f42014-08-19 15:23:24 -0400845bool TIntermOperator::isAssignment() const
846{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300847 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400848}
849
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300850bool TIntermOperator::isMultiplication() const
851{
852 switch (mOp)
853 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500854 case EOpMul:
855 case EOpMatrixTimesMatrix:
856 case EOpMatrixTimesVector:
857 case EOpMatrixTimesScalar:
858 case EOpVectorTimesMatrix:
859 case EOpVectorTimesScalar:
860 return true;
861 default:
862 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300863 }
864}
865
Jamie Madillb1a85f42014-08-19 15:23:24 -0400866bool TIntermOperator::isConstructor() const
867{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300868 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400869}
870
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800871bool TIntermOperator::isFunctionCall() const
872{
873 switch (mOp)
874 {
875 case EOpCallFunctionInAST:
876 case EOpCallBuiltInFunction:
877 case EOpCallInternalRawFunction:
878 return true;
879 default:
880 return false;
881 }
882}
883
Olli Etuaho1dded802016-08-18 18:13:13 +0300884TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
885{
886 if (left.isMatrix())
887 {
888 if (right.isMatrix())
889 {
890 return EOpMatrixTimesMatrix;
891 }
892 else
893 {
894 if (right.isVector())
895 {
896 return EOpMatrixTimesVector;
897 }
898 else
899 {
900 return EOpMatrixTimesScalar;
901 }
902 }
903 }
904 else
905 {
906 if (right.isMatrix())
907 {
908 if (left.isVector())
909 {
910 return EOpVectorTimesMatrix;
911 }
912 else
913 {
914 return EOpMatrixTimesScalar;
915 }
916 }
917 else
918 {
919 // Neither operand is a matrix.
920 if (left.isVector() == right.isVector())
921 {
922 // Leave as component product.
923 return EOpMul;
924 }
925 else
926 {
927 return EOpVectorTimesScalar;
928 }
929 }
930 }
931}
932
933TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
934{
935 if (left.isMatrix())
936 {
937 if (right.isMatrix())
938 {
939 return EOpMatrixTimesMatrixAssign;
940 }
941 else
942 {
943 // right should be scalar, but this may not be validated yet.
944 return EOpMatrixTimesScalarAssign;
945 }
946 }
947 else
948 {
949 if (right.isMatrix())
950 {
951 // Left should be a vector, but this may not be validated yet.
952 return EOpVectorTimesMatrixAssign;
953 }
954 else
955 {
956 // Neither operand is a matrix.
957 if (left.isVector() == right.isVector())
958 {
959 // Leave as component product.
960 return EOpMulAssign;
961 }
962 else
963 {
964 // left should be vector and right should be scalar, but this may not be validated
965 // yet.
966 return EOpVectorTimesScalarAssign;
967 }
968 }
969 }
970}
971
Jamie Madillb1a85f42014-08-19 15:23:24 -0400972//
973// Make sure the type of a unary operator is appropriate for its
974// combination of operation and operand type.
975//
Olli Etuahoa2234302016-08-31 12:05:39 +0300976void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400977{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300978 if (mOp == EOpArrayLength)
979 {
980 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
981 setType(TType(EbtInt, EbpUndefined, EvqConst));
982 return;
983 }
984
Olli Etuahoa2234302016-08-31 12:05:39 +0300985 TQualifier resultQualifier = EvqTemporary;
986 if (mOperand->getQualifier() == EvqConst)
987 resultQualifier = EvqConst;
988
989 unsigned char operandPrimarySize =
990 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400991 switch (mOp)
992 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300993 case EOpFloatBitsToInt:
994 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
995 break;
996 case EOpFloatBitsToUint:
997 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
998 break;
999 case EOpIntBitsToFloat:
1000 case EOpUintBitsToFloat:
1001 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
1002 break;
1003 case EOpPackSnorm2x16:
1004 case EOpPackUnorm2x16:
1005 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001006 case EOpPackUnorm4x8:
1007 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +03001008 setType(TType(EbtUInt, EbpHigh, resultQualifier));
1009 break;
1010 case EOpUnpackSnorm2x16:
1011 case EOpUnpackUnorm2x16:
1012 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
1013 break;
1014 case EOpUnpackHalf2x16:
1015 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
1016 break;
Olli Etuaho25aef452017-01-29 16:15:44 -08001017 case EOpUnpackUnorm4x8:
1018 case EOpUnpackSnorm4x8:
1019 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
1020 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001021 case EOpAny:
1022 case EOpAll:
1023 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1024 break;
1025 case EOpLength:
1026 case EOpDeterminant:
1027 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
1028 break;
1029 case EOpTranspose:
1030 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
1031 static_cast<unsigned char>(mOperand->getType().getRows()),
1032 static_cast<unsigned char>(mOperand->getType().getCols())));
1033 break;
1034 case EOpIsInf:
1035 case EOpIsNan:
1036 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
1037 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001038 case EOpBitfieldReverse:
1039 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
1040 break;
1041 case EOpBitCount:
1042 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1043 break;
1044 case EOpFindLSB:
1045 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1046 break;
1047 case EOpFindMSB:
1048 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
1049 break;
Olli Etuahoa2234302016-08-31 12:05:39 +03001050 default:
1051 setType(mOperand->getType());
1052 mType.setQualifier(resultQualifier);
1053 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001054 }
Olli Etuahoa2234302016-08-31 12:05:39 +03001055}
Jamie Madillb1a85f42014-08-19 15:23:24 -04001056
Olli Etuahob6fa0432016-09-28 16:28:05 +01001057TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001058 : TIntermExpression(TType(EbtFloat, EbpUndefined)),
Olli Etuahob6fa0432016-09-28 16:28:05 +01001059 mOperand(operand),
1060 mSwizzleOffsets(swizzleOffsets)
1061{
1062 ASSERT(mSwizzleOffsets.size() <= 4);
1063 promote();
1064}
1065
Olli Etuahoa2234302016-08-31 12:05:39 +03001066TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
1067 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
1068{
1069 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001070}
1071
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001072TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1073 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
1074{
1075 promote();
1076}
1077
Olli Etuaho0e99b7a2018-01-12 12:05:48 +02001078TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left,
1079 TIntermTyped *right,
1080 int shaderVersion)
1081{
1082 TIntermBinary *node = new TIntermBinary(EOpComma, left, right);
1083 node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right));
1084 return node;
1085}
1086
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001087TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
1088 : TIntermNode(), mSymbol(symbol)
1089{
1090 ASSERT(symbol);
1091 setLine(line);
1092}
1093
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001094TIntermTernary::TIntermTernary(TIntermTyped *cond,
1095 TIntermTyped *trueExpression,
1096 TIntermTyped *falseExpression)
Olli Etuaho2c9cc8b2018-01-09 16:13:02 +02001097 : TIntermExpression(trueExpression->getType()),
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001098 mCondition(cond),
1099 mTrueExpression(trueExpression),
1100 mFalseExpression(falseExpression)
1101{
1102 getTypePointer()->setQualifier(
1103 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1104}
1105
Olli Etuaho81629262017-04-19 11:56:01 +03001106TIntermLoop::TIntermLoop(TLoopType type,
1107 TIntermNode *init,
1108 TIntermTyped *cond,
1109 TIntermTyped *expr,
1110 TIntermBlock *body)
1111 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1112{
1113 // Declaration nodes with no children can appear if all the declarators just added constants to
1114 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1115 if (mInit && mInit->getAsDeclarationNode() &&
1116 mInit->getAsDeclarationNode()->getSequence()->empty())
1117 {
1118 mInit = nullptr;
1119 }
1120}
1121
Olli Etuaho923ecef2017-10-11 12:01:38 +03001122TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
1123 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
1124{
1125 // Prune empty false blocks so that there won't be unnecessary operations done on it.
1126 if (mFalseBlock && mFalseBlock->getSequence()->empty())
1127 {
1128 mFalseBlock = nullptr;
1129 }
1130}
1131
1132TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
1133 : TIntermNode(), mInit(init), mStatementList(statementList)
1134{
1135 ASSERT(mStatementList);
1136}
1137
1138void TIntermSwitch::setStatementList(TIntermBlock *statementList)
1139{
1140 ASSERT(statementList);
1141 mStatementList = statementList;
1142}
1143
Olli Etuahod0bad2c2016-09-09 18:01:16 +03001144// static
1145TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1146 TIntermTyped *trueExpression,
1147 TIntermTyped *falseExpression)
1148{
1149 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1150 falseExpression->getQualifier() == EvqConst)
1151 {
1152 return EvqConst;
1153 }
1154 return EvqTemporary;
1155}
1156
Olli Etuaho765924f2018-01-04 12:48:36 +02001157TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001158{
1159 if (mCondition->getAsConstantUnion())
1160 {
1161 if (mCondition->getAsConstantUnion()->getBConst(0))
1162 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001163 return mTrueExpression;
1164 }
1165 else
1166 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001167 return mFalseExpression;
1168 }
1169 }
1170 return this;
1171}
1172
Olli Etuahob6fa0432016-09-28 16:28:05 +01001173void TIntermSwizzle::promote()
1174{
1175 TQualifier resultQualifier = EvqTemporary;
1176 if (mOperand->getQualifier() == EvqConst)
1177 resultQualifier = EvqConst;
1178
1179 auto numFields = mSwizzleOffsets.size();
1180 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1181 static_cast<unsigned char>(numFields)));
1182}
1183
1184bool TIntermSwizzle::hasDuplicateOffsets() const
1185{
1186 int offsetCount[4] = {0u, 0u, 0u, 0u};
1187 for (const auto offset : mSwizzleOffsets)
1188 {
1189 offsetCount[offset]++;
1190 if (offsetCount[offset] > 1)
1191 {
1192 return true;
1193 }
1194 }
1195 return false;
1196}
1197
Olli Etuaho09b04a22016-12-15 13:30:26 +00001198bool TIntermSwizzle::offsetsMatch(int offset) const
1199{
1200 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1201}
1202
Olli Etuahob6fa0432016-09-28 16:28:05 +01001203void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1204{
1205 for (const int offset : mSwizzleOffsets)
1206 {
1207 switch (offset)
1208 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001209 case 0:
1210 *out << "x";
1211 break;
1212 case 1:
1213 *out << "y";
1214 break;
1215 case 2:
1216 *out << "z";
1217 break;
1218 case 3:
1219 *out << "w";
1220 break;
1221 default:
1222 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001223 }
1224 }
1225}
1226
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001227TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1228 const TIntermTyped *left,
1229 const TIntermTyped *right)
1230{
1231 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1232 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1233 right->getQualifier() != EvqConst)
1234 {
1235 return EvqTemporary;
1236 }
1237 return EvqConst;
1238}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001239
1240// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001241void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001242{
Olli Etuaho1dded802016-08-18 18:13:13 +03001243 ASSERT(!isMultiplication() ||
1244 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1245
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001246 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1247 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001248 if (mOp == EOpComma)
1249 {
1250 setType(mRight->getType());
1251 return;
1252 }
1253
Jamie Madillb1a85f42014-08-19 15:23:24 -04001254 // Base assumption: just make the type the same as the left
1255 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001256 setType(mLeft->getType());
1257
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001258 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001259 // Binary operations results in temporary variables unless both
1260 // operands are const.
1261 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1262 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001263 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001264 getTypePointer()->setQualifier(EvqTemporary);
1265 }
1266
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001267 // Handle indexing ops.
1268 switch (mOp)
1269 {
1270 case EOpIndexDirect:
1271 case EOpIndexIndirect:
1272 if (mLeft->isArray())
1273 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001274 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001275 }
1276 else if (mLeft->isMatrix())
1277 {
1278 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1279 static_cast<unsigned char>(mLeft->getRows())));
1280 }
1281 else if (mLeft->isVector())
1282 {
1283 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1284 }
1285 else
1286 {
1287 UNREACHABLE();
1288 }
1289 return;
1290 case EOpIndexDirectStruct:
1291 {
1292 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1293 const int i = mRight->getAsConstantUnion()->getIConst(0);
1294 setType(*fields[i]->type());
1295 getTypePointer()->setQualifier(resultQualifier);
1296 return;
1297 }
1298 case EOpIndexDirectInterfaceBlock:
1299 {
1300 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1301 const int i = mRight->getAsConstantUnion()->getIConst(0);
1302 setType(*fields[i]->type());
1303 getTypePointer()->setQualifier(resultQualifier);
1304 return;
1305 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001306 default:
1307 break;
1308 }
1309
1310 ASSERT(mLeft->isArray() == mRight->isArray());
1311
1312 // The result gets promoted to the highest precision.
1313 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1314 getTypePointer()->setPrecision(higherPrecision);
1315
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001316 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001317
1318 //
1319 // All scalars or structs. Code after this test assumes this case is removed!
1320 //
1321 if (nominalSize == 1)
1322 {
1323 switch (mOp)
1324 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001325 //
1326 // Promote to conditional
1327 //
1328 case EOpEqual:
1329 case EOpNotEqual:
1330 case EOpLessThan:
1331 case EOpGreaterThan:
1332 case EOpLessThanEqual:
1333 case EOpGreaterThanEqual:
1334 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1335 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001336
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001337 //
1338 // And and Or operate on conditionals
1339 //
1340 case EOpLogicalAnd:
1341 case EOpLogicalXor:
1342 case EOpLogicalOr:
1343 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1344 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1345 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001346
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001347 default:
1348 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001349 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001350 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001351 }
1352
1353 // If we reach here, at least one of the operands is vector or matrix.
1354 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001355 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001356
Jamie Madillb1a85f42014-08-19 15:23:24 -04001357 switch (mOp)
1358 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001359 case EOpMul:
1360 break;
1361 case EOpMatrixTimesScalar:
1362 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001363 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001364 setType(TType(basicType, higherPrecision, resultQualifier,
1365 static_cast<unsigned char>(mRight->getCols()),
1366 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001367 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001368 break;
1369 case EOpMatrixTimesVector:
1370 setType(TType(basicType, higherPrecision, resultQualifier,
1371 static_cast<unsigned char>(mLeft->getRows()), 1));
1372 break;
1373 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001374 setType(TType(basicType, higherPrecision, resultQualifier,
1375 static_cast<unsigned char>(mRight->getCols()),
1376 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001377 break;
1378 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001379 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001380 static_cast<unsigned char>(nominalSize), 1));
1381 break;
1382 case EOpVectorTimesMatrix:
1383 setType(TType(basicType, higherPrecision, resultQualifier,
1384 static_cast<unsigned char>(mRight->getCols()), 1));
1385 break;
1386 case EOpMulAssign:
1387 case EOpVectorTimesScalarAssign:
1388 case EOpVectorTimesMatrixAssign:
1389 case EOpMatrixTimesScalarAssign:
1390 case EOpMatrixTimesMatrixAssign:
1391 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1392 break;
1393 case EOpAssign:
1394 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001395 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1396 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1397 break;
1398 case EOpAdd:
1399 case EOpSub:
1400 case EOpDiv:
1401 case EOpIMod:
1402 case EOpBitShiftLeft:
1403 case EOpBitShiftRight:
1404 case EOpBitwiseAnd:
1405 case EOpBitwiseXor:
1406 case EOpBitwiseOr:
1407 case EOpAddAssign:
1408 case EOpSubAssign:
1409 case EOpDivAssign:
1410 case EOpIModAssign:
1411 case EOpBitShiftLeftAssign:
1412 case EOpBitShiftRightAssign:
1413 case EOpBitwiseAndAssign:
1414 case EOpBitwiseXorAssign:
1415 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001416 {
1417 const int secondarySize =
1418 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1419 setType(TType(basicType, higherPrecision, resultQualifier,
1420 static_cast<unsigned char>(nominalSize),
1421 static_cast<unsigned char>(secondarySize)));
1422 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001423 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001424 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001425 case EOpEqual:
1426 case EOpNotEqual:
1427 case EOpLessThan:
1428 case EOpGreaterThan:
1429 case EOpLessThanEqual:
1430 case EOpGreaterThanEqual:
1431 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1432 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001433 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001434 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001435
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001436 case EOpIndexDirect:
1437 case EOpIndexIndirect:
1438 case EOpIndexDirectInterfaceBlock:
1439 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001440 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001441 UNREACHABLE();
1442 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001443 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001444 UNREACHABLE();
1445 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001446 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001447}
1448
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001449bool TIntermConstantUnion::hasConstantValue() const
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001450{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001451 return true;
1452}
1453
1454const TConstantUnion *TIntermConstantUnion::getConstantValue() const
1455{
1456 return mUnionArrayPointer;
1457}
1458
1459const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
1460 const TConstantUnion *constArray,
1461 int index)
1462{
1463 if (type.isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001464 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001465 ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
1466 TType arrayElementType(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001467 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001468 size_t arrayElementSize = arrayElementType.getObjectSize();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001469 return &constArray[arrayElementSize * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001470 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001471 else if (type.isMatrix())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001472 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001473 ASSERT(index < type.getCols());
1474 int size = type.getRows();
1475 return &constArray[size * index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001476 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001477 else if (type.isVector())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001478 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001479 ASSERT(index < type.getNominalSize());
1480 return &constArray[index];
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001481 }
1482 else
1483 {
1484 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001485 return nullptr;
1486 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001487}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001488
Olli Etuaho765924f2018-01-04 12:48:36 +02001489TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
Olli Etuahob6fa0432016-09-28 16:28:05 +01001490{
1491 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1492 if (operandConstant == nullptr)
1493 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001494 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001495 }
1496
1497 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1498 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1499 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001500 constArray[i] = *TIntermConstantUnion::FoldIndexing(
1501 operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
Olli Etuahob6fa0432016-09-28 16:28:05 +01001502 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001503 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001504}
1505
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001506TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1507{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001508 const TConstantUnion *rightConstant = mRight->getConstantValue();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001509 switch (mOp)
1510 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001511 case EOpComma:
1512 {
1513 if (mLeft->hasSideEffects())
1514 {
1515 return this;
1516 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001517 return mRight;
1518 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001519 case EOpIndexDirect:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001520 case EOpIndexDirectStruct:
1521 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001522 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001523 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001524 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001525 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001526 size_t index = static_cast<size_t>(rightConstant->getIConst());
1527 TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
1528 if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
1529 !leftAggregate->hasSideEffects())
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001530 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001531 ASSERT(index < leftAggregate->getSequence()->size());
1532 // This transformation can't add complexity as we're eliminating the constructor
1533 // entirely.
1534 return leftAggregate->getSequence()->at(index)->getAsTyped();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001535 }
1536
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001537 // If the indexed value is already a constant union, we can't increase duplication of
1538 // data by folding the indexing. Also fold the node in case it's generally beneficial to
1539 // replace this type of node with a constant union even if that would mean duplicating
1540 // data.
1541 if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
1542 {
1543 const TConstantUnion *constantValue = getConstantValue();
1544 if (constantValue == nullptr)
1545 {
1546 return this;
1547 }
1548 return CreateFoldedNode(constantValue, this);
1549 }
1550 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001551 }
1552 case EOpIndexIndirect:
1553 case EOpIndexDirectInterfaceBlock:
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001554 case EOpInitialize:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001555 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001556 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001557 default:
1558 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001559 if (rightConstant == nullptr)
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001560 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001561 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001562 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001563 const TConstantUnion *leftConstant = mLeft->getConstantValue();
1564 if (leftConstant == nullptr)
1565 {
1566 return this;
1567 }
1568 const TConstantUnion *constArray =
1569 TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
1570 mRight->getType(), diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001571 if (!constArray)
1572 {
1573 return this;
1574 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001575 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001576 }
1577 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001578}
1579
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001580bool TIntermBinary::hasConstantValue() const
1581{
1582 switch (mOp)
1583 {
1584 case EOpIndexDirect:
1585 case EOpIndexDirectStruct:
1586 {
1587 if (mLeft->hasConstantValue() && mRight->hasConstantValue())
1588 {
1589 return true;
1590 }
1591 }
1592 default:
1593 break;
1594 }
1595 return false;
1596}
1597
1598const TConstantUnion *TIntermBinary::getConstantValue() const
1599{
1600 if (!hasConstantValue())
1601 {
1602 return nullptr;
1603 }
1604
1605 const TConstantUnion *leftConstantValue = mLeft->getConstantValue();
1606 int index = mRight->getConstantValue()->getIConst();
1607 const TConstantUnion *constIndexingResult = nullptr;
1608 if (mOp == EOpIndexDirect)
1609 {
1610 constIndexingResult =
1611 TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
1612 }
1613 else
1614 {
1615 ASSERT(mOp == EOpIndexDirectStruct);
1616 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1617
1618 size_t previousFieldsSize = 0;
1619 for (int i = 0; i < index; ++i)
1620 {
1621 previousFieldsSize += fields[i]->type()->getObjectSize();
1622 }
1623 constIndexingResult = leftConstantValue + previousFieldsSize;
1624 }
1625 return constIndexingResult;
1626}
1627
Olli Etuahof119a262016-08-19 15:54:22 +03001628TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001629{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301630 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001631
1632 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301633 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001634 // The size of runtime-sized arrays may only be determined at runtime.
1635 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001636 {
1637 return this;
1638 }
1639 constArray = new TConstantUnion[1];
1640 constArray->setIConst(mOperand->getOutermostArraySize());
1641 }
1642 else
1643 {
1644 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1645 if (operandConstant == nullptr)
1646 {
1647 return this;
1648 }
1649
1650 switch (mOp)
1651 {
1652 case EOpAny:
1653 case EOpAll:
1654 case EOpLength:
1655 case EOpTranspose:
1656 case EOpDeterminant:
1657 case EOpInverse:
1658 case EOpPackSnorm2x16:
1659 case EOpUnpackSnorm2x16:
1660 case EOpPackUnorm2x16:
1661 case EOpUnpackUnorm2x16:
1662 case EOpPackHalf2x16:
1663 case EOpUnpackHalf2x16:
1664 case EOpPackUnorm4x8:
1665 case EOpPackSnorm4x8:
1666 case EOpUnpackUnorm4x8:
1667 case EOpUnpackSnorm4x8:
1668 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1669 break;
1670 default:
1671 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1672 break;
1673 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301674 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001675 if (constArray == nullptr)
1676 {
1677 return this;
1678 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001679 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001680}
1681
Olli Etuahof119a262016-08-19 15:54:22 +03001682TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001683{
1684 // Make sure that all params are constant before actual constant folding.
1685 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001686 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001687 if (param->getAsConstantUnion() == nullptr)
1688 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001689 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001690 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001691 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001692 const TConstantUnion *constArray = nullptr;
Olli Etuaho1d122782015-11-06 15:35:17 +02001693 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001694 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001695 if (mType.canReplaceWithConstantUnion())
Olli Etuaho765924f2018-01-04 12:48:36 +02001696 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001697 constArray = getConstantValue();
Olli Etuaho765924f2018-01-04 12:48:36 +02001698 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001699 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001700 else if (CanFoldAggregateBuiltInOp(mOp))
Olli Etuaho2768bc82017-12-12 11:51:48 +02001701 {
Olli Etuahof119a262016-08-19 15:54:22 +03001702 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001703 }
Olli Etuaho765924f2018-01-04 12:48:36 +02001704 if (constArray == nullptr)
1705 {
1706 return this;
1707 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001708 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001709}
1710
Jamie Madillb1a85f42014-08-19 15:23:24 -04001711//
1712// The fold functions see if an operation on a constant can be done in place,
1713// without generating run-time code.
1714//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001715// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001716//
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001717const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
1718 const TConstantUnion *leftArray,
1719 const TType &leftType,
1720 const TConstantUnion *rightArray,
1721 const TType &rightType,
1722 TDiagnostics *diagnostics,
1723 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001724{
Olli Etuahof119a262016-08-19 15:54:22 +03001725 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001726
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001727 size_t objectSize = leftType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001728
1729 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001730 if (rightType.getObjectSize() == 1 && objectSize > 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001731 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001732 rightArray = Vectorize(*rightArray, objectSize);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001733 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001734 else if (rightType.getObjectSize() > 1 && objectSize == 1)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001735 {
1736 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001737 leftArray = Vectorize(*leftArray, rightType.getObjectSize());
1738 objectSize = rightType.getObjectSize();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001739 }
1740
1741 TConstantUnion *resultArray = nullptr;
1742
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001743 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001744 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001745 case EOpAdd:
1746 resultArray = new TConstantUnion[objectSize];
1747 for (size_t i = 0; i < objectSize; i++)
1748 resultArray[i] =
1749 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1750 break;
1751 case EOpSub:
1752 resultArray = new TConstantUnion[objectSize];
1753 for (size_t i = 0; i < objectSize; i++)
1754 resultArray[i] =
1755 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1756 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001757
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001758 case EOpMul:
1759 case EOpVectorTimesScalar:
1760 case EOpMatrixTimesScalar:
1761 resultArray = new TConstantUnion[objectSize];
1762 for (size_t i = 0; i < objectSize; i++)
1763 resultArray[i] =
1764 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1765 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001766
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001767 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001768 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001769 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001770 ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001771
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001772 const int leftCols = leftType.getCols();
1773 const int leftRows = leftType.getRows();
1774 const int rightCols = rightType.getCols();
1775 const int rightRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001776 const int resultCols = rightCols;
1777 const int resultRows = leftRows;
1778
1779 resultArray = new TConstantUnion[resultCols * resultRows];
1780 for (int row = 0; row < resultRows; row++)
1781 {
1782 for (int column = 0; column < resultCols; column++)
1783 {
1784 resultArray[resultRows * column + row].setFConst(0.0f);
1785 for (int i = 0; i < leftCols; i++)
1786 {
1787 resultArray[resultRows * column + row].setFConst(
1788 resultArray[resultRows * column + row].getFConst() +
1789 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001790 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001791 }
1792 }
1793 }
1794 }
1795 break;
1796
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001797 case EOpDiv:
1798 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001799 {
1800 resultArray = new TConstantUnion[objectSize];
1801 for (size_t i = 0; i < objectSize; i++)
1802 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001803 switch (leftType.getBasicType())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001804 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001805 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001806 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001807 ASSERT(op == EOpDiv);
1808 float dividend = leftArray[i].getFConst();
1809 float divisor = rightArray[i].getFConst();
1810 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001811 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001812 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001813 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001814 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001815 line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001816 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001817 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001818 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001819 }
1820 else
1821 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001822 diagnostics->warning(line, "Divide by zero during constant folding",
1823 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001824 bool negativeResult =
1825 std::signbit(dividend) != std::signbit(divisor);
1826 resultArray[i].setFConst(
1827 negativeResult ? -std::numeric_limits<float>::infinity()
1828 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001829 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001830 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001831 else if (gl::isInf(dividend) && gl::isInf(divisor))
1832 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001833 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001834 "Infinity divided by infinity during constant "
1835 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001836 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001837 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1838 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001839 else
1840 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001841 float result = dividend / divisor;
1842 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001843 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001844 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001845 line, "Constant folded division overflowed to infinity", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001846 }
1847 resultArray[i].setFConst(result);
1848 }
1849 break;
1850 }
1851 case EbtInt:
1852 if (rightArray[i] == 0)
1853 {
1854 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001855 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001856 resultArray[i].setIConst(INT_MAX);
1857 }
1858 else
1859 {
1860 int lhs = leftArray[i].getIConst();
1861 int divisor = rightArray[i].getIConst();
1862 if (op == EOpDiv)
1863 {
1864 // Check for the special case where the minimum representable number
1865 // is
1866 // divided by -1. If left alone this leads to integer overflow in
1867 // C++.
1868 // ESSL 3.00.6 section 4.1.3 Integers:
1869 // "However, for the case where the minimum representable value is
1870 // divided by -1, it is allowed to return either the minimum
1871 // representable value or the maximum representable value."
1872 if (lhs == -0x7fffffff - 1 && divisor == -1)
1873 {
1874 resultArray[i].setIConst(0x7fffffff);
1875 }
1876 else
1877 {
1878 resultArray[i].setIConst(lhs / divisor);
1879 }
Olli Etuahod4453572016-09-27 13:21:46 +01001880 }
1881 else
1882 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001883 ASSERT(op == EOpIMod);
1884 if (lhs < 0 || divisor < 0)
1885 {
1886 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1887 // when
1888 // either one of the operands is negative.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001889 diagnostics->warning(line,
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001890 "Negative modulus operator operand "
1891 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001892 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001893 resultArray[i].setIConst(0);
1894 }
1895 else
1896 {
1897 resultArray[i].setIConst(lhs % divisor);
1898 }
Olli Etuahod4453572016-09-27 13:21:46 +01001899 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001900 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001901 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001902
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001903 case EbtUInt:
1904 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001905 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001906 diagnostics->warning(
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001907 line, "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001908 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001909 }
1910 else
1911 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001912 if (op == EOpDiv)
1913 {
1914 resultArray[i].setUConst(leftArray[i].getUConst() /
1915 rightArray[i].getUConst());
1916 }
1917 else
1918 {
1919 ASSERT(op == EOpIMod);
1920 resultArray[i].setUConst(leftArray[i].getUConst() %
1921 rightArray[i].getUConst());
1922 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001923 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001924 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001925
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001926 default:
1927 UNREACHABLE();
1928 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001929 }
1930 }
1931 }
1932 break;
1933
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001934 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001935 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001936 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001937 ASSERT(rightType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001938
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001939 const int matrixCols = leftType.getCols();
1940 const int matrixRows = leftType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001941
1942 resultArray = new TConstantUnion[matrixRows];
1943
1944 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1945 {
1946 resultArray[matrixRow].setFConst(0.0f);
1947 for (int col = 0; col < matrixCols; col++)
1948 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001949 resultArray[matrixRow].setFConst(
1950 resultArray[matrixRow].getFConst() +
1951 leftArray[col * matrixRows + matrixRow].getFConst() *
1952 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001953 }
1954 }
1955 }
1956 break;
1957
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001958 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001959 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001960 // TODO(jmadll): This code should check for overflows.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001961 ASSERT(leftType.getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001962
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001963 const int matrixCols = rightType.getCols();
1964 const int matrixRows = rightType.getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001965
1966 resultArray = new TConstantUnion[matrixCols];
1967
1968 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1969 {
1970 resultArray[matrixCol].setFConst(0.0f);
1971 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1972 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001973 resultArray[matrixCol].setFConst(
1974 resultArray[matrixCol].getFConst() +
1975 leftArray[matrixRow].getFConst() *
1976 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001977 }
1978 }
1979 }
1980 break;
1981
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001982 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001983 {
1984 resultArray = new TConstantUnion[objectSize];
1985 for (size_t i = 0; i < objectSize; i++)
1986 {
1987 resultArray[i] = leftArray[i] && rightArray[i];
1988 }
1989 }
1990 break;
1991
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001992 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001993 {
1994 resultArray = new TConstantUnion[objectSize];
1995 for (size_t i = 0; i < objectSize; i++)
1996 {
1997 resultArray[i] = leftArray[i] || rightArray[i];
1998 }
1999 }
2000 break;
2001
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002002 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002003 {
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002004 ASSERT(leftType.getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002005 resultArray = new TConstantUnion[objectSize];
2006 for (size_t i = 0; i < objectSize; i++)
2007 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03002008 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002009 }
2010 }
2011 break;
2012
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002013 case EOpBitwiseAnd:
2014 resultArray = new TConstantUnion[objectSize];
2015 for (size_t i = 0; i < objectSize; i++)
2016 resultArray[i] = leftArray[i] & rightArray[i];
2017 break;
2018 case EOpBitwiseXor:
2019 resultArray = new TConstantUnion[objectSize];
2020 for (size_t i = 0; i < objectSize; i++)
2021 resultArray[i] = leftArray[i] ^ rightArray[i];
2022 break;
2023 case EOpBitwiseOr:
2024 resultArray = new TConstantUnion[objectSize];
2025 for (size_t i = 0; i < objectSize; i++)
2026 resultArray[i] = leftArray[i] | rightArray[i];
2027 break;
2028 case EOpBitShiftLeft:
2029 resultArray = new TConstantUnion[objectSize];
2030 for (size_t i = 0; i < objectSize; i++)
2031 resultArray[i] =
2032 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
2033 break;
2034 case EOpBitShiftRight:
2035 resultArray = new TConstantUnion[objectSize];
2036 for (size_t i = 0; i < objectSize; i++)
2037 resultArray[i] =
2038 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
2039 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002040
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002041 case EOpLessThan:
2042 ASSERT(objectSize == 1);
2043 resultArray = new TConstantUnion[1];
2044 resultArray->setBConst(*leftArray < *rightArray);
2045 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002046
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002047 case EOpGreaterThan:
2048 ASSERT(objectSize == 1);
2049 resultArray = new TConstantUnion[1];
2050 resultArray->setBConst(*leftArray > *rightArray);
2051 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002052
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002053 case EOpLessThanEqual:
2054 ASSERT(objectSize == 1);
2055 resultArray = new TConstantUnion[1];
2056 resultArray->setBConst(!(*leftArray > *rightArray));
2057 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002058
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002059 case EOpGreaterThanEqual:
2060 ASSERT(objectSize == 1);
2061 resultArray = new TConstantUnion[1];
2062 resultArray->setBConst(!(*leftArray < *rightArray));
2063 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002064
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002065 case EOpEqual:
2066 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002067 {
2068 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002069 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002070 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002071 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002072 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002073 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02002074 equal = false;
2075 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002076 }
2077 }
2078 if (op == EOpEqual)
2079 {
2080 resultArray->setBConst(equal);
2081 }
2082 else
2083 {
2084 resultArray->setBConst(!equal);
2085 }
2086 }
2087 break;
2088
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002089 default:
2090 UNREACHABLE();
2091 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03002092 }
2093 return resultArray;
2094}
2095
Olli Etuahof119a262016-08-19 15:54:22 +03002096// The fold functions do operations on a constant at GLSL compile time, without generating run-time
2097// code. Returns the constant value to keep using. Nullptr should not be returned.
2098TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04002099{
Olli Etuahof119a262016-08-19 15:54:22 +03002100 // Do operations where the return type may have a different number of components compared to the
2101 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04002102
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002103 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002104 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302105
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002106 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302107 TConstantUnion *resultArray = nullptr;
2108 switch (op)
2109 {
Olli Etuahof119a262016-08-19 15:54:22 +03002110 case EOpAny:
2111 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302112 resultArray = new TConstantUnion();
2113 resultArray->setBConst(false);
2114 for (size_t i = 0; i < objectSize; i++)
2115 {
2116 if (operandArray[i].getBConst())
2117 {
2118 resultArray->setBConst(true);
2119 break;
2120 }
2121 }
2122 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302123
Olli Etuahof119a262016-08-19 15:54:22 +03002124 case EOpAll:
2125 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302126 resultArray = new TConstantUnion();
2127 resultArray->setBConst(true);
2128 for (size_t i = 0; i < objectSize; i++)
2129 {
2130 if (!operandArray[i].getBConst())
2131 {
2132 resultArray->setBConst(false);
2133 break;
2134 }
2135 }
2136 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302137
Olli Etuahof119a262016-08-19 15:54:22 +03002138 case EOpLength:
2139 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302140 resultArray = new TConstantUnion();
2141 resultArray->setFConst(VectorLength(operandArray, objectSize));
2142 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302143
Olli Etuahof119a262016-08-19 15:54:22 +03002144 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302145 {
Olli Etuahof119a262016-08-19 15:54:22 +03002146 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302147 resultArray = new TConstantUnion[objectSize];
2148 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002149 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302150 SetUnionArrayFromMatrix(result, resultArray);
2151 break;
2152 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302153
Olli Etuahof119a262016-08-19 15:54:22 +03002154 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302155 {
Olli Etuahof119a262016-08-19 15:54:22 +03002156 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302157 unsigned int size = getType().getNominalSize();
2158 ASSERT(size >= 2 && size <= 4);
2159 resultArray = new TConstantUnion();
2160 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
2161 break;
2162 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302163
Olli Etuahof119a262016-08-19 15:54:22 +03002164 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302165 {
Olli Etuahof119a262016-08-19 15:54:22 +03002166 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302167 unsigned int size = getType().getNominalSize();
2168 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03002169 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05302170 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
2171 SetUnionArrayFromMatrix(result, resultArray);
2172 break;
2173 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302174
Olli Etuahof119a262016-08-19 15:54:22 +03002175 case EOpPackSnorm2x16:
2176 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302177 ASSERT(getType().getNominalSize() == 2);
2178 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002179 resultArray->setUConst(
2180 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302181 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302182
Olli Etuahof119a262016-08-19 15:54:22 +03002183 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302184 {
Olli Etuahof119a262016-08-19 15:54:22 +03002185 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302186 resultArray = new TConstantUnion[2];
2187 float f1, f2;
2188 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2189 resultArray[0].setFConst(f1);
2190 resultArray[1].setFConst(f2);
2191 break;
2192 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302193
Olli Etuahof119a262016-08-19 15:54:22 +03002194 case EOpPackUnorm2x16:
2195 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302196 ASSERT(getType().getNominalSize() == 2);
2197 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002198 resultArray->setUConst(
2199 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302200 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302201
Olli Etuahof119a262016-08-19 15:54:22 +03002202 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302203 {
Olli Etuahof119a262016-08-19 15:54:22 +03002204 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302205 resultArray = new TConstantUnion[2];
2206 float f1, f2;
2207 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2208 resultArray[0].setFConst(f1);
2209 resultArray[1].setFConst(f2);
2210 break;
2211 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302212
Olli Etuahof119a262016-08-19 15:54:22 +03002213 case EOpPackHalf2x16:
2214 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302215 ASSERT(getType().getNominalSize() == 2);
2216 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002217 resultArray->setUConst(
2218 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05302219 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302220
Olli Etuahof119a262016-08-19 15:54:22 +03002221 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302222 {
Olli Etuahof119a262016-08-19 15:54:22 +03002223 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302224 resultArray = new TConstantUnion[2];
2225 float f1, f2;
2226 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2227 resultArray[0].setFConst(f1);
2228 resultArray[1].setFConst(f2);
2229 break;
2230 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302231
Olli Etuaho25aef452017-01-29 16:15:44 -08002232 case EOpPackUnorm4x8:
2233 {
2234 ASSERT(getType().getBasicType() == EbtFloat);
2235 resultArray = new TConstantUnion();
2236 resultArray->setUConst(
2237 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2238 operandArray[2].getFConst(), operandArray[3].getFConst()));
2239 break;
2240 }
2241 case EOpPackSnorm4x8:
2242 {
2243 ASSERT(getType().getBasicType() == EbtFloat);
2244 resultArray = new TConstantUnion();
2245 resultArray->setUConst(
2246 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2247 operandArray[2].getFConst(), operandArray[3].getFConst()));
2248 break;
2249 }
2250 case EOpUnpackUnorm4x8:
2251 {
2252 ASSERT(getType().getBasicType() == EbtUInt);
2253 resultArray = new TConstantUnion[4];
2254 float f[4];
2255 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2256 for (size_t i = 0; i < 4; ++i)
2257 {
2258 resultArray[i].setFConst(f[i]);
2259 }
2260 break;
2261 }
2262 case EOpUnpackSnorm4x8:
2263 {
2264 ASSERT(getType().getBasicType() == EbtUInt);
2265 resultArray = new TConstantUnion[4];
2266 float f[4];
2267 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2268 for (size_t i = 0; i < 4; ++i)
2269 {
2270 resultArray[i].setFConst(f[i]);
2271 }
2272 break;
2273 }
2274
Olli Etuahof119a262016-08-19 15:54:22 +03002275 default:
2276 UNREACHABLE();
2277 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302278 }
2279
2280 return resultArray;
2281}
2282
Olli Etuahof119a262016-08-19 15:54:22 +03002283TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2284 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302285{
Olli Etuahof119a262016-08-19 15:54:22 +03002286 // Do unary operations where each component of the result is computed based on the corresponding
2287 // component of the operand. Also folds normalize, though the divisor in that case takes all
2288 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302289
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002290 const TConstantUnion *operandArray = getConstantValue();
Olli Etuahof119a262016-08-19 15:54:22 +03002291 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002292
2293 size_t objectSize = getType().getObjectSize();
2294
Arun Patoleab2b9a22015-07-06 18:27:56 +05302295 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2296 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302297 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002298 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302299 {
Olli Etuahof119a262016-08-19 15:54:22 +03002300 case EOpNegative:
2301 switch (getType().getBasicType())
2302 {
2303 case EbtFloat:
2304 resultArray[i].setFConst(-operandArray[i].getFConst());
2305 break;
2306 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002307 if (operandArray[i] == std::numeric_limits<int>::min())
2308 {
2309 // The minimum representable integer doesn't have a positive
2310 // counterpart, rather the negation overflows and in ESSL is supposed to
2311 // wrap back to the minimum representable integer. Make sure that we
2312 // don't actually let the negation overflow, which has undefined
2313 // behavior in C++.
2314 resultArray[i].setIConst(std::numeric_limits<int>::min());
2315 }
2316 else
2317 {
2318 resultArray[i].setIConst(-operandArray[i].getIConst());
2319 }
Olli Etuahof119a262016-08-19 15:54:22 +03002320 break;
2321 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002322 if (operandArray[i] == 0x80000000u)
2323 {
2324 resultArray[i].setUConst(0x80000000u);
2325 }
2326 else
2327 {
2328 resultArray[i].setUConst(static_cast<unsigned int>(
2329 -static_cast<int>(operandArray[i].getUConst())));
2330 }
Olli Etuahof119a262016-08-19 15:54:22 +03002331 break;
2332 default:
2333 UNREACHABLE();
2334 return nullptr;
2335 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302336 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302337
Olli Etuahof119a262016-08-19 15:54:22 +03002338 case EOpPositive:
2339 switch (getType().getBasicType())
2340 {
2341 case EbtFloat:
2342 resultArray[i].setFConst(operandArray[i].getFConst());
2343 break;
2344 case EbtInt:
2345 resultArray[i].setIConst(operandArray[i].getIConst());
2346 break;
2347 case EbtUInt:
2348 resultArray[i].setUConst(static_cast<unsigned int>(
2349 static_cast<int>(operandArray[i].getUConst())));
2350 break;
2351 default:
2352 UNREACHABLE();
2353 return nullptr;
2354 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302355 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302356
Olli Etuahof119a262016-08-19 15:54:22 +03002357 case EOpLogicalNot:
2358 switch (getType().getBasicType())
2359 {
2360 case EbtBool:
2361 resultArray[i].setBConst(!operandArray[i].getBConst());
2362 break;
2363 default:
2364 UNREACHABLE();
2365 return nullptr;
2366 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302367 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302368
Olli Etuahof119a262016-08-19 15:54:22 +03002369 case EOpBitwiseNot:
2370 switch (getType().getBasicType())
2371 {
2372 case EbtInt:
2373 resultArray[i].setIConst(~operandArray[i].getIConst());
2374 break;
2375 case EbtUInt:
2376 resultArray[i].setUConst(~operandArray[i].getUConst());
2377 break;
2378 default:
2379 UNREACHABLE();
2380 return nullptr;
2381 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302382 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302383
Olli Etuahof119a262016-08-19 15:54:22 +03002384 case EOpRadians:
2385 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302386 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2387 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302388
Olli Etuahof119a262016-08-19 15:54:22 +03002389 case EOpDegrees:
2390 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302391 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2392 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302393
Olli Etuahof119a262016-08-19 15:54:22 +03002394 case EOpSin:
2395 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302396 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302397
Olli Etuahof119a262016-08-19 15:54:22 +03002398 case EOpCos:
2399 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2400 break;
2401
2402 case EOpTan:
2403 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2404 break;
2405
2406 case EOpAsin:
2407 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2408 // 0.
2409 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2410 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2411 diagnostics, &resultArray[i]);
2412 else
2413 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2414 break;
2415
2416 case EOpAcos:
2417 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2418 // 0.
2419 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2420 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2421 diagnostics, &resultArray[i]);
2422 else
2423 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2424 break;
2425
2426 case EOpAtan:
2427 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2428 break;
2429
2430 case EOpSinh:
2431 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2432 break;
2433
2434 case EOpCosh:
2435 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2436 break;
2437
2438 case EOpTanh:
2439 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2440 break;
2441
2442 case EOpAsinh:
2443 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2444 break;
2445
2446 case EOpAcosh:
2447 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2448 if (operandArray[i].getFConst() < 1.0f)
2449 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2450 diagnostics, &resultArray[i]);
2451 else
2452 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2453 break;
2454
2455 case EOpAtanh:
2456 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2457 // 0.
2458 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2459 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2460 diagnostics, &resultArray[i]);
2461 else
2462 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2463 break;
2464
2465 case EOpAbs:
2466 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302467 {
Olli Etuahof119a262016-08-19 15:54:22 +03002468 case EbtFloat:
2469 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2470 break;
2471 case EbtInt:
2472 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2473 break;
2474 default:
2475 UNREACHABLE();
2476 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302477 }
2478 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002479
2480 case EOpSign:
2481 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302482 {
Olli Etuahof119a262016-08-19 15:54:22 +03002483 case EbtFloat:
2484 {
2485 float fConst = operandArray[i].getFConst();
2486 float fResult = 0.0f;
2487 if (fConst > 0.0f)
2488 fResult = 1.0f;
2489 else if (fConst < 0.0f)
2490 fResult = -1.0f;
2491 resultArray[i].setFConst(fResult);
2492 break;
2493 }
2494 case EbtInt:
2495 {
2496 int iConst = operandArray[i].getIConst();
2497 int iResult = 0;
2498 if (iConst > 0)
2499 iResult = 1;
2500 else if (iConst < 0)
2501 iResult = -1;
2502 resultArray[i].setIConst(iResult);
2503 break;
2504 }
2505 default:
2506 UNREACHABLE();
2507 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302508 }
2509 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302510
Olli Etuahof119a262016-08-19 15:54:22 +03002511 case EOpFloor:
2512 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2513 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302514
Olli Etuahof119a262016-08-19 15:54:22 +03002515 case EOpTrunc:
2516 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2517 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302518
Olli Etuahof119a262016-08-19 15:54:22 +03002519 case EOpRound:
2520 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2521 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302522
Olli Etuahof119a262016-08-19 15:54:22 +03002523 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302524 {
Olli Etuahof119a262016-08-19 15:54:22 +03002525 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302526 float x = operandArray[i].getFConst();
2527 float result;
2528 float fractPart = modff(x, &result);
2529 if (fabsf(fractPart) == 0.5f)
2530 result = 2.0f * roundf(x / 2.0f);
2531 else
2532 result = roundf(x);
2533 resultArray[i].setFConst(result);
2534 break;
2535 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302536
Olli Etuahof119a262016-08-19 15:54:22 +03002537 case EOpCeil:
2538 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2539 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302540
Olli Etuahof119a262016-08-19 15:54:22 +03002541 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302542 {
Olli Etuahof119a262016-08-19 15:54:22 +03002543 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302544 float x = operandArray[i].getFConst();
2545 resultArray[i].setFConst(x - floorf(x));
2546 break;
2547 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302548
Olli Etuahof119a262016-08-19 15:54:22 +03002549 case EOpIsNan:
2550 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302551 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2552 break;
Arun Patole551279e2015-07-07 18:18:23 +05302553
Olli Etuahof119a262016-08-19 15:54:22 +03002554 case EOpIsInf:
2555 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302556 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2557 break;
Arun Patole551279e2015-07-07 18:18:23 +05302558
Olli Etuahof119a262016-08-19 15:54:22 +03002559 case EOpFloatBitsToInt:
2560 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302561 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2562 break;
Arun Patole551279e2015-07-07 18:18:23 +05302563
Olli Etuahof119a262016-08-19 15:54:22 +03002564 case EOpFloatBitsToUint:
2565 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302566 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2567 break;
Arun Patole551279e2015-07-07 18:18:23 +05302568
Olli Etuahof119a262016-08-19 15:54:22 +03002569 case EOpIntBitsToFloat:
2570 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302571 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2572 break;
Arun Patole551279e2015-07-07 18:18:23 +05302573
Olli Etuahof119a262016-08-19 15:54:22 +03002574 case EOpUintBitsToFloat:
2575 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302576 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2577 break;
Arun Patole551279e2015-07-07 18:18:23 +05302578
Olli Etuahof119a262016-08-19 15:54:22 +03002579 case EOpExp:
2580 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2581 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302582
Olli Etuahof119a262016-08-19 15:54:22 +03002583 case EOpLog:
2584 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2585 if (operandArray[i].getFConst() <= 0.0f)
2586 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2587 diagnostics, &resultArray[i]);
2588 else
2589 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2590 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302591
Olli Etuahof119a262016-08-19 15:54:22 +03002592 case EOpExp2:
2593 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2594 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302595
Olli Etuahof119a262016-08-19 15:54:22 +03002596 case EOpLog2:
2597 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2598 // And log2f is not available on some plarforms like old android, so just using
2599 // log(x)/log(2) here.
2600 if (operandArray[i].getFConst() <= 0.0f)
2601 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2602 diagnostics, &resultArray[i]);
2603 else
2604 {
2605 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2606 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2607 }
2608 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302609
Olli Etuahof119a262016-08-19 15:54:22 +03002610 case EOpSqrt:
2611 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2612 if (operandArray[i].getFConst() < 0.0f)
2613 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2614 diagnostics, &resultArray[i]);
2615 else
2616 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2617 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302618
Olli Etuahof119a262016-08-19 15:54:22 +03002619 case EOpInverseSqrt:
2620 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2621 // so getting the square root first using builtin function sqrt() and then taking
2622 // its inverse.
2623 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2624 // result to 0.
2625 if (operandArray[i].getFConst() <= 0.0f)
2626 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2627 diagnostics, &resultArray[i]);
2628 else
2629 {
2630 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2631 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2632 }
2633 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302634
Olli Etuahod68924e2017-01-02 17:34:40 +00002635 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002636 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302637 resultArray[i].setBConst(!operandArray[i].getBConst());
2638 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302639
Olli Etuahof119a262016-08-19 15:54:22 +03002640 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302641 {
Olli Etuahof119a262016-08-19 15:54:22 +03002642 ASSERT(getType().getBasicType() == EbtFloat);
2643 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302644 float length = VectorLength(operandArray, objectSize);
2645 if (length)
2646 resultArray[i].setFConst(x / length);
2647 else
Olli Etuahof119a262016-08-19 15:54:22 +03002648 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2649 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302650 break;
2651 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002652 case EOpBitfieldReverse:
2653 {
2654 uint32_t value;
2655 if (getType().getBasicType() == EbtInt)
2656 {
2657 value = static_cast<uint32_t>(operandArray[i].getIConst());
2658 }
2659 else
2660 {
2661 ASSERT(getType().getBasicType() == EbtUInt);
2662 value = operandArray[i].getUConst();
2663 }
2664 uint32_t result = gl::BitfieldReverse(value);
2665 if (getType().getBasicType() == EbtInt)
2666 {
2667 resultArray[i].setIConst(static_cast<int32_t>(result));
2668 }
2669 else
2670 {
2671 resultArray[i].setUConst(result);
2672 }
2673 break;
2674 }
2675 case EOpBitCount:
2676 {
2677 uint32_t value;
2678 if (getType().getBasicType() == EbtInt)
2679 {
2680 value = static_cast<uint32_t>(operandArray[i].getIConst());
2681 }
2682 else
2683 {
2684 ASSERT(getType().getBasicType() == EbtUInt);
2685 value = operandArray[i].getUConst();
2686 }
2687 int result = gl::BitCount(value);
2688 resultArray[i].setIConst(result);
2689 break;
2690 }
2691 case EOpFindLSB:
2692 {
2693 uint32_t value;
2694 if (getType().getBasicType() == EbtInt)
2695 {
2696 value = static_cast<uint32_t>(operandArray[i].getIConst());
2697 }
2698 else
2699 {
2700 ASSERT(getType().getBasicType() == EbtUInt);
2701 value = operandArray[i].getUConst();
2702 }
2703 resultArray[i].setIConst(gl::FindLSB(value));
2704 break;
2705 }
2706 case EOpFindMSB:
2707 {
2708 uint32_t value;
2709 if (getType().getBasicType() == EbtInt)
2710 {
2711 int intValue = operandArray[i].getIConst();
2712 value = static_cast<uint32_t>(intValue);
2713 if (intValue < 0)
2714 {
2715 // Look for zero instead of one in value. This also handles the intValue ==
2716 // -1 special case, where the return value needs to be -1.
2717 value = ~value;
2718 }
2719 }
2720 else
2721 {
2722 ASSERT(getType().getBasicType() == EbtUInt);
2723 value = operandArray[i].getUConst();
2724 }
2725 resultArray[i].setIConst(gl::FindMSB(value));
2726 break;
2727 }
Olli Etuahof119a262016-08-19 15:54:22 +03002728 case EOpDFdx:
2729 case EOpDFdy:
2730 case EOpFwidth:
2731 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302732 // Derivatives of constant arguments should be 0.
2733 resultArray[i].setFConst(0.0f);
2734 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302735
Olli Etuahof119a262016-08-19 15:54:22 +03002736 default:
2737 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302738 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302739 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002740
Arun Patoleab2b9a22015-07-06 18:27:56 +05302741 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002742}
2743
Olli Etuahof119a262016-08-19 15:54:22 +03002744void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2745 FloatTypeUnaryFunc builtinFunc,
2746 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302747{
2748 ASSERT(builtinFunc);
2749
Olli Etuahof119a262016-08-19 15:54:22 +03002750 ASSERT(getType().getBasicType() == EbtFloat);
2751 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302752}
2753
Jamie Madillb1a85f42014-08-19 15:23:24 -04002754// static
Olli Etuahof119a262016-08-19 15:54:22 +03002755TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2756 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302757{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002758 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002759 TIntermSequence *arguments = aggregate->getSequence();
2760 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2761 std::vector<const TConstantUnion *> unionArrays(argsCount);
2762 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002763 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302764 TBasicType basicType = EbtVoid;
2765 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002766 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302767 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002768 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2769 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302770
2771 if (i == 0)
2772 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002773 basicType = argConstant->getType().getBasicType();
2774 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302775 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002776 unionArrays[i] = argConstant->getConstantValue();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002777 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002778 if (objectSizes[i] > maxObjectSize)
2779 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302780 }
2781
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002782 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302783 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002784 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302785 if (objectSizes[i] != maxObjectSize)
2786 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2787 }
Arun Patole274f0702015-05-05 13:33:30 +05302788
Olli Etuahob43846e2015-06-02 18:18:57 +03002789 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002790
2791 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302792 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002793 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302794 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002795 ASSERT(basicType == EbtFloat);
2796 resultArray = new TConstantUnion[maxObjectSize];
2797 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302798 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002799 float y = unionArrays[0][i].getFConst();
2800 float x = unionArrays[1][i].getFConst();
2801 // Results are undefined if x and y are both 0.
2802 if (x == 0.0f && y == 0.0f)
2803 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2804 else
2805 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302806 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002807 break;
2808 }
Arun Patolebf790422015-05-18 17:53:04 +05302809
Olli Etuaho51182ab2017-01-22 00:12:29 +00002810 case EOpPow:
2811 {
2812 ASSERT(basicType == EbtFloat);
2813 resultArray = new TConstantUnion[maxObjectSize];
2814 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302815 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002816 float x = unionArrays[0][i].getFConst();
2817 float y = unionArrays[1][i].getFConst();
2818 // Results are undefined if x < 0.
2819 // Results are undefined if x = 0 and y <= 0.
2820 if (x < 0.0f)
2821 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2822 else if (x == 0.0f && y <= 0.0f)
2823 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2824 else
2825 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302826 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002827 break;
2828 }
Arun Patolebf790422015-05-18 17:53:04 +05302829
Olli Etuaho51182ab2017-01-22 00:12:29 +00002830 case EOpMod:
2831 {
2832 ASSERT(basicType == EbtFloat);
2833 resultArray = new TConstantUnion[maxObjectSize];
2834 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302835 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002836 float x = unionArrays[0][i].getFConst();
2837 float y = unionArrays[1][i].getFConst();
2838 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302839 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002840 break;
2841 }
Arun Patolebf790422015-05-18 17:53:04 +05302842
Olli Etuaho51182ab2017-01-22 00:12:29 +00002843 case EOpMin:
2844 {
2845 resultArray = new TConstantUnion[maxObjectSize];
2846 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302847 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002848 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302849 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002850 case EbtFloat:
2851 resultArray[i].setFConst(
2852 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2853 break;
2854 case EbtInt:
2855 resultArray[i].setIConst(
2856 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2857 break;
2858 case EbtUInt:
2859 resultArray[i].setUConst(
2860 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2861 break;
2862 default:
2863 UNREACHABLE();
2864 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302865 }
2866 }
2867 break;
Arun Patole274f0702015-05-05 13:33:30 +05302868 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002869
2870 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302871 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002872 resultArray = new TConstantUnion[maxObjectSize];
2873 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302874 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002875 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302876 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002877 case EbtFloat:
2878 resultArray[i].setFConst(
2879 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2880 break;
2881 case EbtInt:
2882 resultArray[i].setIConst(
2883 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2884 break;
2885 case EbtUInt:
2886 resultArray[i].setUConst(
2887 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2888 break;
2889 default:
2890 UNREACHABLE();
2891 break;
Arun Patole274f0702015-05-05 13:33:30 +05302892 }
2893 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002894 break;
Arun Patole274f0702015-05-05 13:33:30 +05302895 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002896
2897 case EOpStep:
2898 {
2899 ASSERT(basicType == EbtFloat);
2900 resultArray = new TConstantUnion[maxObjectSize];
2901 for (size_t i = 0; i < maxObjectSize; i++)
2902 resultArray[i].setFConst(
2903 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2904 break;
2905 }
2906
2907 case EOpLessThanComponentWise:
2908 {
2909 resultArray = new TConstantUnion[maxObjectSize];
2910 for (size_t i = 0; i < maxObjectSize; i++)
2911 {
2912 switch (basicType)
2913 {
2914 case EbtFloat:
2915 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2916 unionArrays[1][i].getFConst());
2917 break;
2918 case EbtInt:
2919 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2920 unionArrays[1][i].getIConst());
2921 break;
2922 case EbtUInt:
2923 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2924 unionArrays[1][i].getUConst());
2925 break;
2926 default:
2927 UNREACHABLE();
2928 break;
2929 }
2930 }
2931 break;
2932 }
2933
2934 case EOpLessThanEqualComponentWise:
2935 {
2936 resultArray = new TConstantUnion[maxObjectSize];
2937 for (size_t i = 0; i < maxObjectSize; i++)
2938 {
2939 switch (basicType)
2940 {
2941 case EbtFloat:
2942 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2943 unionArrays[1][i].getFConst());
2944 break;
2945 case EbtInt:
2946 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2947 unionArrays[1][i].getIConst());
2948 break;
2949 case EbtUInt:
2950 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2951 unionArrays[1][i].getUConst());
2952 break;
2953 default:
2954 UNREACHABLE();
2955 break;
2956 }
2957 }
2958 break;
2959 }
2960
2961 case EOpGreaterThanComponentWise:
2962 {
2963 resultArray = new TConstantUnion[maxObjectSize];
2964 for (size_t i = 0; i < maxObjectSize; i++)
2965 {
2966 switch (basicType)
2967 {
2968 case EbtFloat:
2969 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2970 unionArrays[1][i].getFConst());
2971 break;
2972 case EbtInt:
2973 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2974 unionArrays[1][i].getIConst());
2975 break;
2976 case EbtUInt:
2977 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2978 unionArrays[1][i].getUConst());
2979 break;
2980 default:
2981 UNREACHABLE();
2982 break;
2983 }
2984 }
2985 break;
2986 }
2987 case EOpGreaterThanEqualComponentWise:
2988 {
2989 resultArray = new TConstantUnion[maxObjectSize];
2990 for (size_t i = 0; i < maxObjectSize; i++)
2991 {
2992 switch (basicType)
2993 {
2994 case EbtFloat:
2995 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2996 unionArrays[1][i].getFConst());
2997 break;
2998 case EbtInt:
2999 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
3000 unionArrays[1][i].getIConst());
3001 break;
3002 case EbtUInt:
3003 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
3004 unionArrays[1][i].getUConst());
3005 break;
3006 default:
3007 UNREACHABLE();
3008 break;
3009 }
3010 }
3011 }
3012 break;
3013
3014 case EOpEqualComponentWise:
3015 {
3016 resultArray = new TConstantUnion[maxObjectSize];
3017 for (size_t i = 0; i < maxObjectSize; i++)
3018 {
3019 switch (basicType)
3020 {
3021 case EbtFloat:
3022 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
3023 unionArrays[1][i].getFConst());
3024 break;
3025 case EbtInt:
3026 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
3027 unionArrays[1][i].getIConst());
3028 break;
3029 case EbtUInt:
3030 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
3031 unionArrays[1][i].getUConst());
3032 break;
3033 case EbtBool:
3034 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
3035 unionArrays[1][i].getBConst());
3036 break;
3037 default:
3038 UNREACHABLE();
3039 break;
3040 }
3041 }
3042 break;
3043 }
3044
3045 case EOpNotEqualComponentWise:
3046 {
3047 resultArray = new TConstantUnion[maxObjectSize];
3048 for (size_t i = 0; i < maxObjectSize; i++)
3049 {
3050 switch (basicType)
3051 {
3052 case EbtFloat:
3053 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
3054 unionArrays[1][i].getFConst());
3055 break;
3056 case EbtInt:
3057 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3058 unionArrays[1][i].getIConst());
3059 break;
3060 case EbtUInt:
3061 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3062 unionArrays[1][i].getUConst());
3063 break;
3064 case EbtBool:
3065 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3066 unionArrays[1][i].getBConst());
3067 break;
3068 default:
3069 UNREACHABLE();
3070 break;
3071 }
3072 }
3073 break;
3074 }
3075
3076 case EOpDistance:
3077 {
3078 ASSERT(basicType == EbtFloat);
3079 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3080 resultArray = new TConstantUnion();
3081 for (size_t i = 0; i < maxObjectSize; i++)
3082 {
3083 float x = unionArrays[0][i].getFConst();
3084 float y = unionArrays[1][i].getFConst();
3085 distanceArray[i].setFConst(x - y);
3086 }
3087 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3088 break;
3089 }
3090
3091 case EOpDot:
3092 ASSERT(basicType == EbtFloat);
3093 resultArray = new TConstantUnion();
3094 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3095 break;
3096
3097 case EOpCross:
3098 {
3099 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3100 resultArray = new TConstantUnion[maxObjectSize];
3101 float x0 = unionArrays[0][0].getFConst();
3102 float x1 = unionArrays[0][1].getFConst();
3103 float x2 = unionArrays[0][2].getFConst();
3104 float y0 = unionArrays[1][0].getFConst();
3105 float y1 = unionArrays[1][1].getFConst();
3106 float y2 = unionArrays[1][2].getFConst();
3107 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3108 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3109 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3110 break;
3111 }
3112
3113 case EOpReflect:
3114 {
3115 ASSERT(basicType == EbtFloat);
3116 // genType reflect (genType I, genType N) :
3117 // For the incident vector I and surface orientation N, returns the reflection
3118 // direction:
3119 // I - 2 * dot(N, I) * N.
3120 resultArray = new TConstantUnion[maxObjectSize];
3121 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3122 for (size_t i = 0; i < maxObjectSize; i++)
3123 {
3124 float result = unionArrays[0][i].getFConst() -
3125 2.0f * dotProduct * unionArrays[1][i].getFConst();
3126 resultArray[i].setFConst(result);
3127 }
3128 break;
3129 }
3130
3131 case EOpMulMatrixComponentWise:
3132 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003133 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3134 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003135 // Perform component-wise matrix multiplication.
3136 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003137 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003138 angle::Matrix<float> result =
3139 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3140 SetUnionArrayFromMatrix(result, resultArray);
3141 break;
3142 }
3143
3144 case EOpOuterProduct:
3145 {
3146 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003147 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3148 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003149 resultArray = new TConstantUnion[numRows * numCols];
3150 angle::Matrix<float> result =
3151 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3152 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3153 SetUnionArrayFromMatrix(result, resultArray);
3154 break;
3155 }
3156
3157 case EOpClamp:
3158 {
3159 resultArray = new TConstantUnion[maxObjectSize];
3160 for (size_t i = 0; i < maxObjectSize; i++)
3161 {
3162 switch (basicType)
3163 {
3164 case EbtFloat:
3165 {
3166 float x = unionArrays[0][i].getFConst();
3167 float min = unionArrays[1][i].getFConst();
3168 float max = unionArrays[2][i].getFConst();
3169 // Results are undefined if min > max.
3170 if (min > max)
3171 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3172 &resultArray[i]);
3173 else
3174 resultArray[i].setFConst(gl::clamp(x, min, max));
3175 break;
3176 }
3177
3178 case EbtInt:
3179 {
3180 int x = unionArrays[0][i].getIConst();
3181 int min = unionArrays[1][i].getIConst();
3182 int max = unionArrays[2][i].getIConst();
3183 // Results are undefined if min > max.
3184 if (min > max)
3185 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3186 &resultArray[i]);
3187 else
3188 resultArray[i].setIConst(gl::clamp(x, min, max));
3189 break;
3190 }
3191 case EbtUInt:
3192 {
3193 unsigned int x = unionArrays[0][i].getUConst();
3194 unsigned int min = unionArrays[1][i].getUConst();
3195 unsigned int max = unionArrays[2][i].getUConst();
3196 // Results are undefined if min > max.
3197 if (min > max)
3198 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3199 &resultArray[i]);
3200 else
3201 resultArray[i].setUConst(gl::clamp(x, min, max));
3202 break;
3203 }
3204 default:
3205 UNREACHABLE();
3206 break;
3207 }
3208 }
3209 break;
3210 }
3211
3212 case EOpMix:
3213 {
3214 ASSERT(basicType == EbtFloat);
3215 resultArray = new TConstantUnion[maxObjectSize];
3216 for (size_t i = 0; i < maxObjectSize; i++)
3217 {
3218 float x = unionArrays[0][i].getFConst();
3219 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003220 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003221 if (type == EbtFloat)
3222 {
3223 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3224 float a = unionArrays[2][i].getFConst();
3225 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3226 }
3227 else // 3rd parameter is EbtBool
3228 {
3229 ASSERT(type == EbtBool);
3230 // Selects which vector each returned component comes from.
3231 // For a component of a that is false, the corresponding component of x is
3232 // returned.
3233 // For a component of a that is true, the corresponding component of y is
3234 // returned.
3235 bool a = unionArrays[2][i].getBConst();
3236 resultArray[i].setFConst(a ? y : x);
3237 }
3238 }
3239 break;
3240 }
3241
3242 case EOpSmoothStep:
3243 {
3244 ASSERT(basicType == EbtFloat);
3245 resultArray = new TConstantUnion[maxObjectSize];
3246 for (size_t i = 0; i < maxObjectSize; i++)
3247 {
3248 float edge0 = unionArrays[0][i].getFConst();
3249 float edge1 = unionArrays[1][i].getFConst();
3250 float x = unionArrays[2][i].getFConst();
3251 // Results are undefined if edge0 >= edge1.
3252 if (edge0 >= edge1)
3253 {
3254 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3255 }
3256 else
3257 {
3258 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3259 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3260 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3261 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3262 }
3263 }
3264 break;
3265 }
3266
Olli Etuaho74da73f2017-02-01 15:37:48 +00003267 case EOpLdexp:
3268 {
3269 resultArray = new TConstantUnion[maxObjectSize];
3270 for (size_t i = 0; i < maxObjectSize; i++)
3271 {
3272 float x = unionArrays[0][i].getFConst();
3273 int exp = unionArrays[1][i].getIConst();
3274 if (exp > 128)
3275 {
3276 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3277 }
3278 else
3279 {
3280 resultArray[i].setFConst(gl::Ldexp(x, exp));
3281 }
3282 }
3283 break;
3284 }
3285
Jamie Madille72595b2017-06-06 15:12:26 -04003286 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003287 {
3288 ASSERT(basicType == EbtFloat);
3289 // genType faceforward(genType N, genType I, genType Nref) :
3290 // If dot(Nref, I) < 0 return N, otherwise return -N.
3291 resultArray = new TConstantUnion[maxObjectSize];
3292 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3293 for (size_t i = 0; i < maxObjectSize; i++)
3294 {
3295 if (dotProduct < 0)
3296 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3297 else
3298 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3299 }
3300 break;
3301 }
3302
3303 case EOpRefract:
3304 {
3305 ASSERT(basicType == EbtFloat);
3306 // genType refract(genType I, genType N, float eta) :
3307 // For the incident vector I and surface normal N, and the ratio of indices of
3308 // refraction eta,
3309 // return the refraction vector. The result is computed by
3310 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3311 // if (k < 0.0)
3312 // return genType(0.0)
3313 // else
3314 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3315 resultArray = new TConstantUnion[maxObjectSize];
3316 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3317 for (size_t i = 0; i < maxObjectSize; i++)
3318 {
3319 float eta = unionArrays[2][i].getFConst();
3320 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3321 if (k < 0.0f)
3322 resultArray[i].setFConst(0.0f);
3323 else
3324 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3325 (eta * dotProduct + sqrtf(k)) *
3326 unionArrays[1][i].getFConst());
3327 }
3328 break;
3329 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003330 case EOpBitfieldExtract:
3331 {
3332 resultArray = new TConstantUnion[maxObjectSize];
3333 for (size_t i = 0; i < maxObjectSize; ++i)
3334 {
3335 int offset = unionArrays[1][0].getIConst();
3336 int bits = unionArrays[2][0].getIConst();
3337 if (bits == 0)
3338 {
3339 if (aggregate->getBasicType() == EbtInt)
3340 {
3341 resultArray[i].setIConst(0);
3342 }
3343 else
3344 {
3345 ASSERT(aggregate->getBasicType() == EbtUInt);
3346 resultArray[i].setUConst(0);
3347 }
3348 }
3349 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3350 {
3351 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3352 &resultArray[i]);
3353 }
3354 else
3355 {
3356 // bits can be 32 here, so we need to avoid bit shift overflow.
3357 uint32_t maskMsb = 1u << (bits - 1);
3358 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3359 if (aggregate->getBasicType() == EbtInt)
3360 {
3361 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3362 uint32_t resultUnsigned = (value & mask) >> offset;
3363 if ((resultUnsigned & maskMsb) != 0)
3364 {
3365 // The most significant bits (from bits+1 to the most significant bit)
3366 // should be set to 1.
3367 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3368 resultUnsigned |= higherBitsMask;
3369 }
3370 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3371 }
3372 else
3373 {
3374 ASSERT(aggregate->getBasicType() == EbtUInt);
3375 uint32_t value = unionArrays[0][i].getUConst();
3376 resultArray[i].setUConst((value & mask) >> offset);
3377 }
3378 }
3379 }
3380 break;
3381 }
3382 case EOpBitfieldInsert:
3383 {
3384 resultArray = new TConstantUnion[maxObjectSize];
3385 for (size_t i = 0; i < maxObjectSize; ++i)
3386 {
3387 int offset = unionArrays[2][0].getIConst();
3388 int bits = unionArrays[3][0].getIConst();
3389 if (bits == 0)
3390 {
3391 if (aggregate->getBasicType() == EbtInt)
3392 {
3393 int32_t base = unionArrays[0][i].getIConst();
3394 resultArray[i].setIConst(base);
3395 }
3396 else
3397 {
3398 ASSERT(aggregate->getBasicType() == EbtUInt);
3399 uint32_t base = unionArrays[0][i].getUConst();
3400 resultArray[i].setUConst(base);
3401 }
3402 }
3403 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3404 {
3405 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3406 &resultArray[i]);
3407 }
3408 else
3409 {
3410 // bits can be 32 here, so we need to avoid bit shift overflow.
3411 uint32_t maskMsb = 1u << (bits - 1);
3412 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3413 uint32_t baseMask = ~insertMask;
3414 if (aggregate->getBasicType() == EbtInt)
3415 {
3416 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3417 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3418 uint32_t resultUnsigned =
3419 (base & baseMask) | ((insert << offset) & insertMask);
3420 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3421 }
3422 else
3423 {
3424 ASSERT(aggregate->getBasicType() == EbtUInt);
3425 uint32_t base = unionArrays[0][i].getUConst();
3426 uint32_t insert = unionArrays[1][i].getUConst();
3427 resultArray[i].setUConst((base & baseMask) |
3428 ((insert << offset) & insertMask));
3429 }
3430 }
3431 }
3432 break;
3433 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003434
3435 default:
3436 UNREACHABLE();
3437 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303438 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003439 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303440}
3441
Jamie Madill45bcc782016-11-07 13:58:48 -05003442} // namespace sh