blob: 088eb4320c5672904f920a5895dc3915bdf1b708 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040021#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040023#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040024
Jamie Madill45bcc782016-11-07 13:58:48 -050025namespace sh
26{
27
Jamie Madillb1a85f42014-08-19 15:23:24 -040028namespace
29{
30
Jamie Madilld7b1ab52016-12-12 14:42:19 -050031const float kPi = 3.14159265358979323846f;
Arun Patole9dea48f2015-04-02 11:45:09 +053032const float kDegreesToRadiansMultiplier = kPi / 180.0f;
33const float kRadiansToDegreesMultiplier = 180.0f / kPi;
34
Jamie Madillb1a85f42014-08-19 15:23:24 -040035TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
36{
37 return left > right ? left : right;
38}
39
Arun Patole274f0702015-05-05 13:33:30 +053040TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
41{
42 TConstantUnion *constUnion = new TConstantUnion[size];
43 for (unsigned int i = 0; i < size; ++i)
Jamie Madilld7b1ab52016-12-12 14:42:19 -050044 constUnion[i] = constant;
Arun Patole274f0702015-05-05 13:33:30 +053045
46 return constUnion;
47}
48
Olli Etuahof119a262016-08-19 15:54:22 +030049void UndefinedConstantFoldingError(const TSourceLoc &loc,
50 TOperator op,
51 TBasicType basicType,
52 TDiagnostics *diagnostics,
53 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053054{
Olli Etuahof119a262016-08-19 15:54:22 +030055 diagnostics->warning(loc, "operation result is undefined for the values passed in",
Olli Etuaho4de340a2016-12-16 09:32:03 +000056 GetOperatorString(op));
Arun Patolebf790422015-05-18 17:53:04 +053057
58 switch (basicType)
59 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050060 case EbtFloat:
61 result->setFConst(0.0f);
62 break;
63 case EbtInt:
64 result->setIConst(0);
65 break;
66 case EbtUInt:
67 result->setUConst(0u);
68 break;
69 case EbtBool:
70 result->setBConst(false);
71 break;
72 default:
73 break;
Arun Patolebf790422015-05-18 17:53:04 +053074 }
75}
76
Olli Etuaho5c0e0232015-11-11 15:55:59 +020077float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053078{
79 float result = 0.0f;
80 for (size_t i = 0; i < paramArraySize; i++)
81 {
82 float f = paramArray[i].getFConst();
83 result += f * f;
84 }
85 return sqrtf(result);
86}
87
Olli Etuaho5c0e0232015-11-11 15:55:59 +020088float VectorDotProduct(const TConstantUnion *paramArray1,
89 const TConstantUnion *paramArray2,
90 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053091{
92 float result = 0.0f;
93 for (size_t i = 0; i < paramArraySize; i++)
94 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
95 return result;
96}
97
Olli Etuaho3272a6d2016-08-29 17:54:50 +030098TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
Olli Etuaho7c3848e2015-11-04 13:19:17 +020099 const TIntermTyped *originalNode,
100 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300101{
102 if (constArray == nullptr)
103 {
104 return nullptr;
105 }
106 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200107 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300108 folded->setLine(originalNode->getLine());
109 return folded;
110}
111
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200112angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
113 const unsigned int &rows,
114 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530115{
116 std::vector<float> elements;
117 for (size_t i = 0; i < rows * cols; i++)
118 elements.push_back(paramArray[i].getFConst());
119 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300120 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
121 // so that the created matrix will have the expected dimensions after the transpose.
122 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530123}
124
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200125angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530126{
127 std::vector<float> elements;
128 for (size_t i = 0; i < size * size; i++)
129 elements.push_back(paramArray[i].getFConst());
130 // Transpose is used since the Matrix constructor expects arguments in row-major order,
131 // whereas the paramArray is in column-major order.
132 return angle::Matrix<float>(elements, size).transpose();
133}
134
135void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
136{
137 // Transpose is used since the input Matrix is in row-major order,
138 // whereas the actual result should be in column-major order.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500139 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530140 std::vector<float> resultElements = result.elements();
141 for (size_t i = 0; i < resultElements.size(); i++)
142 resultArray[i].setFConst(resultElements[i]);
143}
144
Jamie Madillb1a85f42014-08-19 15:23:24 -0400145} // namespace anonymous
146
Jamie Madillb1a85f42014-08-19 15:23:24 -0400147////////////////////////////////////////////////////////////////
148//
149// Member functions of the nodes used for building the tree.
150//
151////////////////////////////////////////////////////////////////
152
Olli Etuahod2a67b92014-10-21 16:42:57 +0300153void TIntermTyped::setTypePreservePrecision(const TType &t)
154{
155 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500156 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300157 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
158 mType.setPrecision(precision);
159}
160
Jamie Madillb1a85f42014-08-19 15:23:24 -0400161#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500162 if (node == original) \
163 { \
164 node = static_cast<type *>(replacement); \
165 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400166 }
167
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500168bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400169{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300170 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400171 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
172 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
173 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100174 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400175 return false;
176}
177
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500178bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400179{
180 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
181 return false;
182}
183
Olli Etuahob6fa0432016-09-28 16:28:05 +0100184bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
185{
186 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
187 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
188 return false;
189}
190
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500191bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400192{
193 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
194 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
195 return false;
196}
197
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500198bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400199{
Olli Etuahoa2234302016-08-31 12:05:39 +0300200 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400201 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
202 return false;
203}
204
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000205bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
206{
207 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
208 return false;
209}
210
Olli Etuaho336b1472016-10-05 16:37:55 +0100211bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
212{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000213 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100214 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
215 return false;
216}
217
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500218bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400219{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100220 return replaceChildNodeInternal(original, replacement);
221}
222
223bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
224{
225 return replaceChildNodeInternal(original, replacement);
226}
227
Olli Etuaho16c745a2017-01-16 17:02:27 +0000228bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
229{
230 return replaceChildNodeInternal(original, replacement);
231}
232
Olli Etuaho13389b62016-10-16 11:48:18 +0100233bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
234{
235 return replaceChildNodeInternal(original, replacement);
236}
237
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100238bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
239{
240 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400241 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100242 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400243 }
244 return false;
245}
246
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100247bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
248 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300249{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100250 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300251 {
252 if (*it == original)
253 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100254 it = getSequence()->erase(it);
255 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300256 return true;
257 }
258 }
259 return false;
260}
261
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100262bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
263 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300264{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100265 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300266 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300267 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300268 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100269 auto it = getSequence()->begin() + position;
270 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300271 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300272}
273
Olli Etuaho195be942017-12-04 23:40:14 +0200274TIntermSymbol::TIntermSymbol(const TVariable *variable)
275 : TIntermTyped(variable->getType()), mId(variable->uniqueId()), mSymbol(variable->name())
276{
277 if (variable->symbolType() == SymbolType::AngleInternal)
278 {
279 mSymbol.setInternal(true);
280 }
281}
282
Olli Etuahofe486322017-03-21 09:30:54 +0000283TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
284 TIntermSequence *arguments)
285{
286 TIntermAggregate *callNode =
287 new TIntermAggregate(func.getReturnType(), EOpCallFunctionInAST, arguments);
288 callNode->getFunctionSymbolInfo()->setFromFunction(func);
289 return callNode;
290}
291
292TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TType &type,
293 const TSymbolUniqueId &id,
294 const TName &name,
295 TIntermSequence *arguments)
296{
297 TIntermAggregate *callNode = new TIntermAggregate(type, EOpCallFunctionInAST, arguments);
298 callNode->getFunctionSymbolInfo()->setId(id);
299 callNode->getFunctionSymbolInfo()->setNameObj(name);
300 return callNode;
301}
302
303TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
304 TIntermSequence *arguments)
305{
306 TIntermAggregate *callNode =
307 new TIntermAggregate(func.getReturnType(), EOpCallBuiltInFunction, arguments);
308 callNode->getFunctionSymbolInfo()->setFromFunction(func);
309 // Note that name needs to be set before texture function type is determined.
310 callNode->setBuiltInFunctionPrecision();
311 return callNode;
312}
313
314TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000315 TIntermSequence *arguments)
316{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300317 return new TIntermAggregate(type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000318}
319
320TIntermAggregate *TIntermAggregate::Create(const TType &type,
321 TOperator op,
322 TIntermSequence *arguments)
323{
324 TIntermAggregate *node = new TIntermAggregate(type, op, arguments);
325 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
326 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
327 ASSERT(!node->isConstructor()); // Should use CreateConstructor
328 return node;
329}
330
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800331TIntermAggregate::TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments)
332 : TIntermOperator(op), mUseEmulatedFunction(false), mGotPrecisionFromChildren(false)
333{
334 if (arguments != nullptr)
335 {
336 mArguments.swap(*arguments);
337 }
338 setTypePrecisionAndQualifier(type);
339}
340
341void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
342{
343 setType(type);
344 mType.setQualifier(EvqTemporary);
345 if (!isFunctionCall())
346 {
347 if (isConstructor())
348 {
349 // Structs should not be precision qualified, the individual members may be.
350 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300351 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800352 {
353 setPrecisionFromChildren();
354 }
355 }
356 else
357 {
358 setPrecisionForBuiltInOp();
359 }
360 if (areChildrenConstQualified())
361 {
362 mType.setQualifier(EvqConst);
363 }
364 }
365}
366
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200367bool TIntermAggregate::areChildrenConstQualified()
368{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800369 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200370 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800371 TIntermTyped *typedArg = arg->getAsTyped();
372 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200373 {
374 return false;
375 }
376 }
377 return true;
378}
379
Olli Etuahod2a67b92014-10-21 16:42:57 +0300380void TIntermAggregate::setPrecisionFromChildren()
381{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300382 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300383 if (getBasicType() == EbtBool)
384 {
385 mType.setPrecision(EbpUndefined);
386 return;
387 }
388
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500389 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800390 TIntermSequence::iterator childIter = mArguments.begin();
391 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300392 {
393 TIntermTyped *typed = (*childIter)->getAsTyped();
394 if (typed)
395 precision = GetHigherPrecision(typed->getPrecision(), precision);
396 ++childIter;
397 }
398 mType.setPrecision(precision);
399}
400
Olli Etuaho9250cb22017-01-21 10:51:27 +0000401void TIntermAggregate::setPrecisionForBuiltInOp()
402{
403 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800404 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000405 if (!setPrecisionForSpecialBuiltInOp())
406 {
407 setPrecisionFromChildren();
408 }
409}
410
411bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
412{
413 switch (mOp)
414 {
415 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800416 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
417 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000418 return true;
419 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800420 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
421 mArguments[1]->getAsTyped()->getPrecision()));
422 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000423 return true;
424 case EOpUaddCarry:
425 case EOpUsubBorrow:
426 mType.setPrecision(EbpHigh);
427 return true;
428 default:
429 return false;
430 }
431}
432
Olli Etuahod2a67b92014-10-21 16:42:57 +0300433void TIntermAggregate::setBuiltInFunctionPrecision()
434{
435 // All built-ins returning bool should be handled as ops, not functions.
436 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800437 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300438
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800439 TPrecision precision = EbpUndefined;
440 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300441 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800442 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300443 // ESSL spec section 8: texture functions get their precision from the sampler.
444 if (typed && IsSampler(typed->getBasicType()))
445 {
446 precision = typed->getPrecision();
447 break;
448 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300449 }
450 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
451 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100452 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300453 mType.setPrecision(EbpHigh);
454 else
455 mType.setPrecision(precision);
456}
457
Olli Etuahof2209f72017-04-01 12:45:55 +0300458TString TIntermAggregate::getSymbolTableMangledName() const
459{
460 ASSERT(!isConstructor());
461 switch (mOp)
462 {
463 case EOpCallInternalRawFunction:
464 case EOpCallBuiltInFunction:
465 case EOpCallFunctionInAST:
466 return TFunction::GetMangledNameFromCall(mFunctionInfo.getName(), mArguments);
467 default:
468 TString opString = GetOperatorString(mOp);
469 return TFunction::GetMangledNameFromCall(opString, mArguments);
470 }
471}
472
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300473bool TIntermAggregate::hasSideEffects() const
474{
475 if (isFunctionCall() && mFunctionInfo.isKnownToNotHaveSideEffects())
476 {
477 for (TIntermNode *arg : mArguments)
478 {
479 if (arg->getAsTyped()->hasSideEffects())
480 {
481 return true;
482 }
483 }
484 return false;
485 }
486 // Conservatively assume most aggregate operators have side-effects
487 return true;
488}
489
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100490void TIntermBlock::appendStatement(TIntermNode *statement)
491{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300492 // Declaration nodes with no children can appear if it was an empty declaration or if all the
493 // declarators just added constants to the symbol table instead of generating code. We still
494 // need to add the declaration to the AST in that case because it might be relevant to the
495 // validity of switch/case.
496 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100497 {
498 mStatements.push_back(statement);
499 }
500}
501
Olli Etuaho16c745a2017-01-16 17:02:27 +0000502void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
503{
504 ASSERT(parameter != nullptr);
505 mParameters.push_back(parameter);
506}
507
Olli Etuaho13389b62016-10-16 11:48:18 +0100508void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
509{
510 ASSERT(declarator != nullptr);
511 ASSERT(declarator->getAsSymbolNode() != nullptr ||
512 (declarator->getAsBinaryNode() != nullptr &&
513 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
514 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300515 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100516 mDeclarators.push_back(declarator);
517}
518
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300519bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
520{
521 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
522 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
523 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
524 return false;
525}
526
Olli Etuaho57961272016-09-14 13:57:46 +0300527bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400528{
529 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100530 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
531 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400532 return false;
533}
534
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500535bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200536{
537 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100538 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300539 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200540 return false;
541}
542
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500543bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200544{
545 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
546 return false;
547}
548
Olli Etuahod7a25242015-08-18 13:49:45 +0300549TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
550{
551 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
552 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
553 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
554 mLine = node.mLine;
555}
556
Olli Etuahod4f4c112016-04-15 15:11:24 +0300557bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
558{
559 TIntermAggregate *constructor = getAsAggregate();
560 if (!constructor || !constructor->isConstructor())
561 {
562 return false;
563 }
564 for (TIntermNode *&node : *constructor->getSequence())
565 {
566 if (!node->getAsConstantUnion())
567 return false;
568 }
569 return true;
570}
571
Olli Etuahod7a25242015-08-18 13:49:45 +0300572TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
573{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200574 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300575}
576
Olli Etuahobd674552016-10-06 13:28:42 +0100577void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
578{
Olli Etuaho54a29ff2017-11-28 17:35:20 +0200579 setName(function.name());
Olli Etuahofe486322017-03-21 09:30:54 +0000580 setId(TSymbolUniqueId(function));
581}
582
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300583TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id)
584 : mId(new TSymbolUniqueId(id)), mKnownToNotHaveSideEffects(false)
Olli Etuahofe486322017-03-21 09:30:54 +0000585{
586}
587
588TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300589 : mName(info.mName), mId(nullptr), mKnownToNotHaveSideEffects(info.mKnownToNotHaveSideEffects)
Olli Etuahofe486322017-03-21 09:30:54 +0000590{
591 if (info.mId)
592 {
593 mId = new TSymbolUniqueId(*info.mId);
594 }
595}
596
597TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
598{
599 mName = info.mName;
600 if (info.mId)
601 {
602 mId = new TSymbolUniqueId(*info.mId);
603 }
604 else
605 {
606 mId = nullptr;
607 }
608 return *this;
609}
610
611void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
612{
613 mId = new TSymbolUniqueId(id);
614}
615
616const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
617{
618 ASSERT(mId);
619 return *mId;
Olli Etuahobd674552016-10-06 13:28:42 +0100620}
621
Olli Etuahod7a25242015-08-18 13:49:45 +0300622TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
623 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300624 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100625 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
626 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300627{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800628 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300629 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800630 TIntermTyped *typedArg = arg->getAsTyped();
631 ASSERT(typedArg != nullptr);
632 TIntermTyped *argCopy = typedArg->deepCopy();
633 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300634 }
635}
636
Olli Etuahofe486322017-03-21 09:30:54 +0000637TIntermAggregate *TIntermAggregate::shallowCopy() const
638{
639 TIntermSequence *copySeq = new TIntermSequence();
640 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
641 TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq);
642 *copyNode->getFunctionSymbolInfo() = mFunctionInfo;
643 copyNode->setLine(mLine);
644 return copyNode;
645}
646
Olli Etuahob6fa0432016-09-28 16:28:05 +0100647TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
648{
649 TIntermTyped *operandCopy = node.mOperand->deepCopy();
650 ASSERT(operandCopy != nullptr);
651 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000652 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100653}
654
Olli Etuahod7a25242015-08-18 13:49:45 +0300655TIntermBinary::TIntermBinary(const TIntermBinary &node)
656 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
657{
658 TIntermTyped *leftCopy = node.mLeft->deepCopy();
659 TIntermTyped *rightCopy = node.mRight->deepCopy();
660 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
661 mLeft = leftCopy;
662 mRight = rightCopy;
663}
664
665TIntermUnary::TIntermUnary(const TIntermUnary &node)
666 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
667{
668 TIntermTyped *operandCopy = node.mOperand->deepCopy();
669 ASSERT(operandCopy != nullptr);
670 mOperand = operandCopy;
671}
672
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300673TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300674{
Olli Etuahod7a25242015-08-18 13:49:45 +0300675 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300676 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
677 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300678 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300679 mCondition = conditionCopy;
680 mTrueExpression = trueCopy;
681 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300682}
683
Jamie Madillb1a85f42014-08-19 15:23:24 -0400684bool TIntermOperator::isAssignment() const
685{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300686 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400687}
688
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300689bool TIntermOperator::isMultiplication() const
690{
691 switch (mOp)
692 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500693 case EOpMul:
694 case EOpMatrixTimesMatrix:
695 case EOpMatrixTimesVector:
696 case EOpMatrixTimesScalar:
697 case EOpVectorTimesMatrix:
698 case EOpVectorTimesScalar:
699 return true;
700 default:
701 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300702 }
703}
704
Jamie Madillb1a85f42014-08-19 15:23:24 -0400705bool TIntermOperator::isConstructor() const
706{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300707 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400708}
709
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800710bool TIntermOperator::isFunctionCall() const
711{
712 switch (mOp)
713 {
714 case EOpCallFunctionInAST:
715 case EOpCallBuiltInFunction:
716 case EOpCallInternalRawFunction:
717 return true;
718 default:
719 return false;
720 }
721}
722
Olli Etuaho1dded802016-08-18 18:13:13 +0300723TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
724{
725 if (left.isMatrix())
726 {
727 if (right.isMatrix())
728 {
729 return EOpMatrixTimesMatrix;
730 }
731 else
732 {
733 if (right.isVector())
734 {
735 return EOpMatrixTimesVector;
736 }
737 else
738 {
739 return EOpMatrixTimesScalar;
740 }
741 }
742 }
743 else
744 {
745 if (right.isMatrix())
746 {
747 if (left.isVector())
748 {
749 return EOpVectorTimesMatrix;
750 }
751 else
752 {
753 return EOpMatrixTimesScalar;
754 }
755 }
756 else
757 {
758 // Neither operand is a matrix.
759 if (left.isVector() == right.isVector())
760 {
761 // Leave as component product.
762 return EOpMul;
763 }
764 else
765 {
766 return EOpVectorTimesScalar;
767 }
768 }
769 }
770}
771
772TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
773{
774 if (left.isMatrix())
775 {
776 if (right.isMatrix())
777 {
778 return EOpMatrixTimesMatrixAssign;
779 }
780 else
781 {
782 // right should be scalar, but this may not be validated yet.
783 return EOpMatrixTimesScalarAssign;
784 }
785 }
786 else
787 {
788 if (right.isMatrix())
789 {
790 // Left should be a vector, but this may not be validated yet.
791 return EOpVectorTimesMatrixAssign;
792 }
793 else
794 {
795 // Neither operand is a matrix.
796 if (left.isVector() == right.isVector())
797 {
798 // Leave as component product.
799 return EOpMulAssign;
800 }
801 else
802 {
803 // left should be vector and right should be scalar, but this may not be validated
804 // yet.
805 return EOpVectorTimesScalarAssign;
806 }
807 }
808 }
809}
810
Jamie Madillb1a85f42014-08-19 15:23:24 -0400811//
812// Make sure the type of a unary operator is appropriate for its
813// combination of operation and operand type.
814//
Olli Etuahoa2234302016-08-31 12:05:39 +0300815void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400816{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300817 if (mOp == EOpArrayLength)
818 {
819 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
820 setType(TType(EbtInt, EbpUndefined, EvqConst));
821 return;
822 }
823
Olli Etuahoa2234302016-08-31 12:05:39 +0300824 TQualifier resultQualifier = EvqTemporary;
825 if (mOperand->getQualifier() == EvqConst)
826 resultQualifier = EvqConst;
827
828 unsigned char operandPrimarySize =
829 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400830 switch (mOp)
831 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300832 case EOpFloatBitsToInt:
833 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
834 break;
835 case EOpFloatBitsToUint:
836 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
837 break;
838 case EOpIntBitsToFloat:
839 case EOpUintBitsToFloat:
840 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
841 break;
842 case EOpPackSnorm2x16:
843 case EOpPackUnorm2x16:
844 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800845 case EOpPackUnorm4x8:
846 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300847 setType(TType(EbtUInt, EbpHigh, resultQualifier));
848 break;
849 case EOpUnpackSnorm2x16:
850 case EOpUnpackUnorm2x16:
851 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
852 break;
853 case EOpUnpackHalf2x16:
854 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
855 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800856 case EOpUnpackUnorm4x8:
857 case EOpUnpackSnorm4x8:
858 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
859 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300860 case EOpAny:
861 case EOpAll:
862 setType(TType(EbtBool, EbpUndefined, resultQualifier));
863 break;
864 case EOpLength:
865 case EOpDeterminant:
866 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
867 break;
868 case EOpTranspose:
869 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
870 static_cast<unsigned char>(mOperand->getType().getRows()),
871 static_cast<unsigned char>(mOperand->getType().getCols())));
872 break;
873 case EOpIsInf:
874 case EOpIsNan:
875 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
876 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000877 case EOpBitfieldReverse:
878 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
879 break;
880 case EOpBitCount:
881 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
882 break;
883 case EOpFindLSB:
884 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
885 break;
886 case EOpFindMSB:
887 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
888 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300889 default:
890 setType(mOperand->getType());
891 mType.setQualifier(resultQualifier);
892 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400893 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300894}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400895
Olli Etuahob6fa0432016-09-28 16:28:05 +0100896TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
897 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
898 mOperand(operand),
899 mSwizzleOffsets(swizzleOffsets)
900{
901 ASSERT(mSwizzleOffsets.size() <= 4);
902 promote();
903}
904
Olli Etuahoa2234302016-08-31 12:05:39 +0300905TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
906 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
907{
908 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400909}
910
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300911TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
912 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
913{
914 promote();
915}
916
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000917TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
918 : TIntermNode(), mSymbol(symbol)
919{
920 ASSERT(symbol);
921 setLine(line);
922}
923
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300924TIntermTernary::TIntermTernary(TIntermTyped *cond,
925 TIntermTyped *trueExpression,
926 TIntermTyped *falseExpression)
927 : TIntermTyped(trueExpression->getType()),
928 mCondition(cond),
929 mTrueExpression(trueExpression),
930 mFalseExpression(falseExpression)
931{
932 getTypePointer()->setQualifier(
933 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
934}
935
Olli Etuaho81629262017-04-19 11:56:01 +0300936TIntermLoop::TIntermLoop(TLoopType type,
937 TIntermNode *init,
938 TIntermTyped *cond,
939 TIntermTyped *expr,
940 TIntermBlock *body)
941 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
942{
943 // Declaration nodes with no children can appear if all the declarators just added constants to
944 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
945 if (mInit && mInit->getAsDeclarationNode() &&
946 mInit->getAsDeclarationNode()->getSequence()->empty())
947 {
948 mInit = nullptr;
949 }
950}
951
Olli Etuaho923ecef2017-10-11 12:01:38 +0300952TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
953 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
954{
955 // Prune empty false blocks so that there won't be unnecessary operations done on it.
956 if (mFalseBlock && mFalseBlock->getSequence()->empty())
957 {
958 mFalseBlock = nullptr;
959 }
960}
961
962TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
963 : TIntermNode(), mInit(init), mStatementList(statementList)
964{
965 ASSERT(mStatementList);
966}
967
968void TIntermSwitch::setStatementList(TIntermBlock *statementList)
969{
970 ASSERT(statementList);
971 mStatementList = statementList;
972}
973
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300974// static
975TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
976 TIntermTyped *trueExpression,
977 TIntermTyped *falseExpression)
978{
979 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
980 falseExpression->getQualifier() == EvqConst)
981 {
982 return EvqConst;
983 }
984 return EvqTemporary;
985}
986
Olli Etuahoeb7f90f2017-07-07 17:25:23 +0300987TIntermTyped *TIntermTernary::fold()
988{
989 if (mCondition->getAsConstantUnion())
990 {
991 if (mCondition->getAsConstantUnion()->getBConst(0))
992 {
993 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
994 return mTrueExpression;
995 }
996 else
997 {
998 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
999 return mFalseExpression;
1000 }
1001 }
1002 return this;
1003}
1004
Olli Etuahob6fa0432016-09-28 16:28:05 +01001005void TIntermSwizzle::promote()
1006{
1007 TQualifier resultQualifier = EvqTemporary;
1008 if (mOperand->getQualifier() == EvqConst)
1009 resultQualifier = EvqConst;
1010
1011 auto numFields = mSwizzleOffsets.size();
1012 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1013 static_cast<unsigned char>(numFields)));
1014}
1015
1016bool TIntermSwizzle::hasDuplicateOffsets() const
1017{
1018 int offsetCount[4] = {0u, 0u, 0u, 0u};
1019 for (const auto offset : mSwizzleOffsets)
1020 {
1021 offsetCount[offset]++;
1022 if (offsetCount[offset] > 1)
1023 {
1024 return true;
1025 }
1026 }
1027 return false;
1028}
1029
Olli Etuaho09b04a22016-12-15 13:30:26 +00001030bool TIntermSwizzle::offsetsMatch(int offset) const
1031{
1032 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1033}
1034
Olli Etuahob6fa0432016-09-28 16:28:05 +01001035void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1036{
1037 for (const int offset : mSwizzleOffsets)
1038 {
1039 switch (offset)
1040 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001041 case 0:
1042 *out << "x";
1043 break;
1044 case 1:
1045 *out << "y";
1046 break;
1047 case 2:
1048 *out << "z";
1049 break;
1050 case 3:
1051 *out << "w";
1052 break;
1053 default:
1054 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001055 }
1056 }
1057}
1058
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001059TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1060 const TIntermTyped *left,
1061 const TIntermTyped *right)
1062{
1063 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1064 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1065 right->getQualifier() != EvqConst)
1066 {
1067 return EvqTemporary;
1068 }
1069 return EvqConst;
1070}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001071
1072// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001073void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001074{
Olli Etuaho1dded802016-08-18 18:13:13 +03001075 ASSERT(!isMultiplication() ||
1076 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1077
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001078 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1079 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001080 if (mOp == EOpComma)
1081 {
1082 setType(mRight->getType());
1083 return;
1084 }
1085
Jamie Madillb1a85f42014-08-19 15:23:24 -04001086 // Base assumption: just make the type the same as the left
1087 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001088 setType(mLeft->getType());
1089
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001090 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001091 // Binary operations results in temporary variables unless both
1092 // operands are const.
1093 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1094 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001095 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001096 getTypePointer()->setQualifier(EvqTemporary);
1097 }
1098
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001099 // Handle indexing ops.
1100 switch (mOp)
1101 {
1102 case EOpIndexDirect:
1103 case EOpIndexIndirect:
1104 if (mLeft->isArray())
1105 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001106 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001107 }
1108 else if (mLeft->isMatrix())
1109 {
1110 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1111 static_cast<unsigned char>(mLeft->getRows())));
1112 }
1113 else if (mLeft->isVector())
1114 {
1115 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1116 }
1117 else
1118 {
1119 UNREACHABLE();
1120 }
1121 return;
1122 case EOpIndexDirectStruct:
1123 {
1124 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1125 const int i = mRight->getAsConstantUnion()->getIConst(0);
1126 setType(*fields[i]->type());
1127 getTypePointer()->setQualifier(resultQualifier);
1128 return;
1129 }
1130 case EOpIndexDirectInterfaceBlock:
1131 {
1132 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1133 const int i = mRight->getAsConstantUnion()->getIConst(0);
1134 setType(*fields[i]->type());
1135 getTypePointer()->setQualifier(resultQualifier);
1136 return;
1137 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001138 default:
1139 break;
1140 }
1141
1142 ASSERT(mLeft->isArray() == mRight->isArray());
1143
1144 // The result gets promoted to the highest precision.
1145 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1146 getTypePointer()->setPrecision(higherPrecision);
1147
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001148 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001149
1150 //
1151 // All scalars or structs. Code after this test assumes this case is removed!
1152 //
1153 if (nominalSize == 1)
1154 {
1155 switch (mOp)
1156 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001157 //
1158 // Promote to conditional
1159 //
1160 case EOpEqual:
1161 case EOpNotEqual:
1162 case EOpLessThan:
1163 case EOpGreaterThan:
1164 case EOpLessThanEqual:
1165 case EOpGreaterThanEqual:
1166 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1167 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001168
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001169 //
1170 // And and Or operate on conditionals
1171 //
1172 case EOpLogicalAnd:
1173 case EOpLogicalXor:
1174 case EOpLogicalOr:
1175 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1176 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1177 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001178
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001179 default:
1180 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001181 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001182 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001183 }
1184
1185 // If we reach here, at least one of the operands is vector or matrix.
1186 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001187 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001188
Jamie Madillb1a85f42014-08-19 15:23:24 -04001189 switch (mOp)
1190 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001191 case EOpMul:
1192 break;
1193 case EOpMatrixTimesScalar:
1194 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001195 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001196 setType(TType(basicType, higherPrecision, resultQualifier,
1197 static_cast<unsigned char>(mRight->getCols()),
1198 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001199 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001200 break;
1201 case EOpMatrixTimesVector:
1202 setType(TType(basicType, higherPrecision, resultQualifier,
1203 static_cast<unsigned char>(mLeft->getRows()), 1));
1204 break;
1205 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001206 setType(TType(basicType, higherPrecision, resultQualifier,
1207 static_cast<unsigned char>(mRight->getCols()),
1208 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001209 break;
1210 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001211 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001212 static_cast<unsigned char>(nominalSize), 1));
1213 break;
1214 case EOpVectorTimesMatrix:
1215 setType(TType(basicType, higherPrecision, resultQualifier,
1216 static_cast<unsigned char>(mRight->getCols()), 1));
1217 break;
1218 case EOpMulAssign:
1219 case EOpVectorTimesScalarAssign:
1220 case EOpVectorTimesMatrixAssign:
1221 case EOpMatrixTimesScalarAssign:
1222 case EOpMatrixTimesMatrixAssign:
1223 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1224 break;
1225 case EOpAssign:
1226 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001227 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1228 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1229 break;
1230 case EOpAdd:
1231 case EOpSub:
1232 case EOpDiv:
1233 case EOpIMod:
1234 case EOpBitShiftLeft:
1235 case EOpBitShiftRight:
1236 case EOpBitwiseAnd:
1237 case EOpBitwiseXor:
1238 case EOpBitwiseOr:
1239 case EOpAddAssign:
1240 case EOpSubAssign:
1241 case EOpDivAssign:
1242 case EOpIModAssign:
1243 case EOpBitShiftLeftAssign:
1244 case EOpBitShiftRightAssign:
1245 case EOpBitwiseAndAssign:
1246 case EOpBitwiseXorAssign:
1247 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001248 {
1249 const int secondarySize =
1250 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1251 setType(TType(basicType, higherPrecision, resultQualifier,
1252 static_cast<unsigned char>(nominalSize),
1253 static_cast<unsigned char>(secondarySize)));
1254 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001255 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001256 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001257 case EOpEqual:
1258 case EOpNotEqual:
1259 case EOpLessThan:
1260 case EOpGreaterThan:
1261 case EOpLessThanEqual:
1262 case EOpGreaterThanEqual:
1263 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1264 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001265 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001266 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001267
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001268 case EOpIndexDirect:
1269 case EOpIndexIndirect:
1270 case EOpIndexDirectInterfaceBlock:
1271 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001272 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001273 UNREACHABLE();
1274 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001275 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001276 UNREACHABLE();
1277 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001278 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001279}
1280
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001281const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001282{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001283 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001284 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001285 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001286 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001287 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001288 size_t arrayElementSize = arrayElementType.getObjectSize();
1289 return &mUnionArrayPointer[arrayElementSize * index];
1290 }
1291 else if (isMatrix())
1292 {
1293 ASSERT(index < getType().getCols());
1294 int size = getType().getRows();
1295 return &mUnionArrayPointer[size * index];
1296 }
1297 else if (isVector())
1298 {
1299 ASSERT(index < getType().getNominalSize());
1300 return &mUnionArrayPointer[index];
1301 }
1302 else
1303 {
1304 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001305 return nullptr;
1306 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001307}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001308
Olli Etuahob6fa0432016-09-28 16:28:05 +01001309TIntermTyped *TIntermSwizzle::fold()
1310{
1311 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1312 if (operandConstant == nullptr)
1313 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001314 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001315 }
1316
1317 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1318 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1319 {
1320 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1321 }
1322 return CreateFoldedNode(constArray, this, mType.getQualifier());
1323}
1324
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001325TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1326{
1327 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1328 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1329 switch (mOp)
1330 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001331 case EOpComma:
1332 {
1333 if (mLeft->hasSideEffects())
1334 {
1335 return this;
1336 }
1337 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1338 return mRight;
1339 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001340 case EOpIndexDirect:
1341 {
1342 if (leftConstant == nullptr || rightConstant == nullptr)
1343 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001344 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001345 }
1346 int index = rightConstant->getIConst(0);
1347
1348 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001349 if (!constArray)
1350 {
1351 return this;
1352 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001353 return CreateFoldedNode(constArray, this, mType.getQualifier());
1354 }
1355 case EOpIndexDirectStruct:
1356 {
1357 if (leftConstant == nullptr || rightConstant == nullptr)
1358 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001359 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001360 }
1361 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1362 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1363
1364 size_t previousFieldsSize = 0;
1365 for (size_t i = 0; i < index; ++i)
1366 {
1367 previousFieldsSize += fields[i]->type()->getObjectSize();
1368 }
1369
1370 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1371 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1372 }
1373 case EOpIndexIndirect:
1374 case EOpIndexDirectInterfaceBlock:
1375 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001376 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001377 default:
1378 {
1379 if (leftConstant == nullptr || rightConstant == nullptr)
1380 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001381 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001382 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001383 TConstantUnion *constArray =
1384 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001385 if (!constArray)
1386 {
1387 return this;
1388 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001389
1390 // Nodes may be constant folded without being qualified as constant.
1391 return CreateFoldedNode(constArray, this, mType.getQualifier());
1392 }
1393 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001394}
1395
Olli Etuahof119a262016-08-19 15:54:22 +03001396TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001397{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301398 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001399
1400 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301401 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001402 // The size of runtime-sized arrays may only be determined at runtime.
1403 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001404 {
1405 return this;
1406 }
1407 constArray = new TConstantUnion[1];
1408 constArray->setIConst(mOperand->getOutermostArraySize());
1409 }
1410 else
1411 {
1412 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1413 if (operandConstant == nullptr)
1414 {
1415 return this;
1416 }
1417
1418 switch (mOp)
1419 {
1420 case EOpAny:
1421 case EOpAll:
1422 case EOpLength:
1423 case EOpTranspose:
1424 case EOpDeterminant:
1425 case EOpInverse:
1426 case EOpPackSnorm2x16:
1427 case EOpUnpackSnorm2x16:
1428 case EOpPackUnorm2x16:
1429 case EOpUnpackUnorm2x16:
1430 case EOpPackHalf2x16:
1431 case EOpUnpackHalf2x16:
1432 case EOpPackUnorm4x8:
1433 case EOpPackSnorm4x8:
1434 case EOpUnpackUnorm4x8:
1435 case EOpUnpackSnorm4x8:
1436 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1437 break;
1438 default:
1439 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1440 break;
1441 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301442 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001443 if (constArray == nullptr)
1444 {
1445 return this;
1446 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001447
1448 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001449 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001450}
1451
Olli Etuahof119a262016-08-19 15:54:22 +03001452TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001453{
1454 // Make sure that all params are constant before actual constant folding.
1455 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001456 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001457 if (param->getAsConstantUnion() == nullptr)
1458 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001459 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001460 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001461 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001462 TConstantUnion *constArray = nullptr;
1463 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001464 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001465 else
Olli Etuahof119a262016-08-19 15:54:22 +03001466 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001467
1468 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001469 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001470}
1471
Jamie Madillb1a85f42014-08-19 15:23:24 -04001472//
1473// The fold functions see if an operation on a constant can be done in place,
1474// without generating run-time code.
1475//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001476// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001477//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001478TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1479 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001480 TDiagnostics *diagnostics,
1481 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001482{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001483 const TConstantUnion *leftArray = getUnionArrayPointer();
1484 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001485
Olli Etuahof119a262016-08-19 15:54:22 +03001486 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001487
1488 size_t objectSize = getType().getObjectSize();
1489
1490 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1491 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1492 {
1493 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1494 }
1495 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1496 {
1497 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001498 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001499 objectSize = rightNode->getType().getObjectSize();
1500 }
1501
1502 TConstantUnion *resultArray = nullptr;
1503
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001504 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001505 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001506 case EOpAdd:
1507 resultArray = new TConstantUnion[objectSize];
1508 for (size_t i = 0; i < objectSize; i++)
1509 resultArray[i] =
1510 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1511 break;
1512 case EOpSub:
1513 resultArray = new TConstantUnion[objectSize];
1514 for (size_t i = 0; i < objectSize; i++)
1515 resultArray[i] =
1516 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1517 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001518
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001519 case EOpMul:
1520 case EOpVectorTimesScalar:
1521 case EOpMatrixTimesScalar:
1522 resultArray = new TConstantUnion[objectSize];
1523 for (size_t i = 0; i < objectSize; i++)
1524 resultArray[i] =
1525 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1526 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001527
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001528 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001529 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001530 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001531 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001532
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001533 const int leftCols = getCols();
1534 const int leftRows = getRows();
1535 const int rightCols = rightNode->getType().getCols();
1536 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001537 const int resultCols = rightCols;
1538 const int resultRows = leftRows;
1539
1540 resultArray = new TConstantUnion[resultCols * resultRows];
1541 for (int row = 0; row < resultRows; row++)
1542 {
1543 for (int column = 0; column < resultCols; column++)
1544 {
1545 resultArray[resultRows * column + row].setFConst(0.0f);
1546 for (int i = 0; i < leftCols; i++)
1547 {
1548 resultArray[resultRows * column + row].setFConst(
1549 resultArray[resultRows * column + row].getFConst() +
1550 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001551 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001552 }
1553 }
1554 }
1555 }
1556 break;
1557
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001558 case EOpDiv:
1559 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001560 {
1561 resultArray = new TConstantUnion[objectSize];
1562 for (size_t i = 0; i < objectSize; i++)
1563 {
1564 switch (getType().getBasicType())
1565 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001566 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001567 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001568 ASSERT(op == EOpDiv);
1569 float dividend = leftArray[i].getFConst();
1570 float divisor = rightArray[i].getFConst();
1571 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001572 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001573 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001574 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001575 diagnostics->warning(
1576 getLine(),
1577 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001578 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001579 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001580 }
1581 else
1582 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001583 diagnostics->warning(getLine(),
1584 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001585 bool negativeResult =
1586 std::signbit(dividend) != std::signbit(divisor);
1587 resultArray[i].setFConst(
1588 negativeResult ? -std::numeric_limits<float>::infinity()
1589 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001590 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001591 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001592 else if (gl::isInf(dividend) && gl::isInf(divisor))
1593 {
1594 diagnostics->warning(getLine(),
1595 "Infinity divided by infinity during constant "
1596 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001597 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001598 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1599 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001600 else
1601 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001602 float result = dividend / divisor;
1603 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001604 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001605 diagnostics->warning(
1606 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001607 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001608 }
1609 resultArray[i].setFConst(result);
1610 }
1611 break;
1612 }
1613 case EbtInt:
1614 if (rightArray[i] == 0)
1615 {
1616 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001617 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 resultArray[i].setIConst(INT_MAX);
1619 }
1620 else
1621 {
1622 int lhs = leftArray[i].getIConst();
1623 int divisor = rightArray[i].getIConst();
1624 if (op == EOpDiv)
1625 {
1626 // Check for the special case where the minimum representable number
1627 // is
1628 // divided by -1. If left alone this leads to integer overflow in
1629 // C++.
1630 // ESSL 3.00.6 section 4.1.3 Integers:
1631 // "However, for the case where the minimum representable value is
1632 // divided by -1, it is allowed to return either the minimum
1633 // representable value or the maximum representable value."
1634 if (lhs == -0x7fffffff - 1 && divisor == -1)
1635 {
1636 resultArray[i].setIConst(0x7fffffff);
1637 }
1638 else
1639 {
1640 resultArray[i].setIConst(lhs / divisor);
1641 }
Olli Etuahod4453572016-09-27 13:21:46 +01001642 }
1643 else
1644 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001645 ASSERT(op == EOpIMod);
1646 if (lhs < 0 || divisor < 0)
1647 {
1648 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1649 // when
1650 // either one of the operands is negative.
1651 diagnostics->warning(getLine(),
1652 "Negative modulus operator operand "
1653 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001654 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001655 resultArray[i].setIConst(0);
1656 }
1657 else
1658 {
1659 resultArray[i].setIConst(lhs % divisor);
1660 }
Olli Etuahod4453572016-09-27 13:21:46 +01001661 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001662 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001663 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001664
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001665 case EbtUInt:
1666 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001667 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001668 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001669 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001670 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001671 }
1672 else
1673 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001674 if (op == EOpDiv)
1675 {
1676 resultArray[i].setUConst(leftArray[i].getUConst() /
1677 rightArray[i].getUConst());
1678 }
1679 else
1680 {
1681 ASSERT(op == EOpIMod);
1682 resultArray[i].setUConst(leftArray[i].getUConst() %
1683 rightArray[i].getUConst());
1684 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001685 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001686 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001687
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001688 default:
1689 UNREACHABLE();
1690 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001691 }
1692 }
1693 }
1694 break;
1695
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001696 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001697 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001698 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001699 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001700
1701 const int matrixCols = getCols();
1702 const int matrixRows = getRows();
1703
1704 resultArray = new TConstantUnion[matrixRows];
1705
1706 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1707 {
1708 resultArray[matrixRow].setFConst(0.0f);
1709 for (int col = 0; col < matrixCols; col++)
1710 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001711 resultArray[matrixRow].setFConst(
1712 resultArray[matrixRow].getFConst() +
1713 leftArray[col * matrixRows + matrixRow].getFConst() *
1714 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001715 }
1716 }
1717 }
1718 break;
1719
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001720 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001721 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001722 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001723 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001724
1725 const int matrixCols = rightNode->getType().getCols();
1726 const int matrixRows = rightNode->getType().getRows();
1727
1728 resultArray = new TConstantUnion[matrixCols];
1729
1730 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1731 {
1732 resultArray[matrixCol].setFConst(0.0f);
1733 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1734 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001735 resultArray[matrixCol].setFConst(
1736 resultArray[matrixCol].getFConst() +
1737 leftArray[matrixRow].getFConst() *
1738 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001739 }
1740 }
1741 }
1742 break;
1743
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001744 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001745 {
1746 resultArray = new TConstantUnion[objectSize];
1747 for (size_t i = 0; i < objectSize; i++)
1748 {
1749 resultArray[i] = leftArray[i] && rightArray[i];
1750 }
1751 }
1752 break;
1753
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001754 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001755 {
1756 resultArray = new TConstantUnion[objectSize];
1757 for (size_t i = 0; i < objectSize; i++)
1758 {
1759 resultArray[i] = leftArray[i] || rightArray[i];
1760 }
1761 }
1762 break;
1763
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001764 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001765 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001766 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001767 resultArray = new TConstantUnion[objectSize];
1768 for (size_t i = 0; i < objectSize; i++)
1769 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001770 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001771 }
1772 }
1773 break;
1774
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001775 case EOpBitwiseAnd:
1776 resultArray = new TConstantUnion[objectSize];
1777 for (size_t i = 0; i < objectSize; i++)
1778 resultArray[i] = leftArray[i] & rightArray[i];
1779 break;
1780 case EOpBitwiseXor:
1781 resultArray = new TConstantUnion[objectSize];
1782 for (size_t i = 0; i < objectSize; i++)
1783 resultArray[i] = leftArray[i] ^ rightArray[i];
1784 break;
1785 case EOpBitwiseOr:
1786 resultArray = new TConstantUnion[objectSize];
1787 for (size_t i = 0; i < objectSize; i++)
1788 resultArray[i] = leftArray[i] | rightArray[i];
1789 break;
1790 case EOpBitShiftLeft:
1791 resultArray = new TConstantUnion[objectSize];
1792 for (size_t i = 0; i < objectSize; i++)
1793 resultArray[i] =
1794 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1795 break;
1796 case EOpBitShiftRight:
1797 resultArray = new TConstantUnion[objectSize];
1798 for (size_t i = 0; i < objectSize; i++)
1799 resultArray[i] =
1800 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1801 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001802
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001803 case EOpLessThan:
1804 ASSERT(objectSize == 1);
1805 resultArray = new TConstantUnion[1];
1806 resultArray->setBConst(*leftArray < *rightArray);
1807 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001808
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001809 case EOpGreaterThan:
1810 ASSERT(objectSize == 1);
1811 resultArray = new TConstantUnion[1];
1812 resultArray->setBConst(*leftArray > *rightArray);
1813 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001814
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001815 case EOpLessThanEqual:
1816 ASSERT(objectSize == 1);
1817 resultArray = new TConstantUnion[1];
1818 resultArray->setBConst(!(*leftArray > *rightArray));
1819 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001820
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001821 case EOpGreaterThanEqual:
1822 ASSERT(objectSize == 1);
1823 resultArray = new TConstantUnion[1];
1824 resultArray->setBConst(!(*leftArray < *rightArray));
1825 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001826
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001827 case EOpEqual:
1828 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001829 {
1830 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001831 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001832 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001833 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001834 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001835 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001836 equal = false;
1837 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001838 }
1839 }
1840 if (op == EOpEqual)
1841 {
1842 resultArray->setBConst(equal);
1843 }
1844 else
1845 {
1846 resultArray->setBConst(!equal);
1847 }
1848 }
1849 break;
1850
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001851 default:
1852 UNREACHABLE();
1853 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001854 }
1855 return resultArray;
1856}
1857
Olli Etuahof119a262016-08-19 15:54:22 +03001858// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1859// code. Returns the constant value to keep using. Nullptr should not be returned.
1860TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001861{
Olli Etuahof119a262016-08-19 15:54:22 +03001862 // Do operations where the return type may have a different number of components compared to the
1863 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001864
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001865 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001866 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301867
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001868 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301869 TConstantUnion *resultArray = nullptr;
1870 switch (op)
1871 {
Olli Etuahof119a262016-08-19 15:54:22 +03001872 case EOpAny:
1873 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301874 resultArray = new TConstantUnion();
1875 resultArray->setBConst(false);
1876 for (size_t i = 0; i < objectSize; i++)
1877 {
1878 if (operandArray[i].getBConst())
1879 {
1880 resultArray->setBConst(true);
1881 break;
1882 }
1883 }
1884 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301885
Olli Etuahof119a262016-08-19 15:54:22 +03001886 case EOpAll:
1887 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301888 resultArray = new TConstantUnion();
1889 resultArray->setBConst(true);
1890 for (size_t i = 0; i < objectSize; i++)
1891 {
1892 if (!operandArray[i].getBConst())
1893 {
1894 resultArray->setBConst(false);
1895 break;
1896 }
1897 }
1898 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301899
Olli Etuahof119a262016-08-19 15:54:22 +03001900 case EOpLength:
1901 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301902 resultArray = new TConstantUnion();
1903 resultArray->setFConst(VectorLength(operandArray, objectSize));
1904 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301905
Olli Etuahof119a262016-08-19 15:54:22 +03001906 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301907 {
Olli Etuahof119a262016-08-19 15:54:22 +03001908 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301909 resultArray = new TConstantUnion[objectSize];
1910 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001911 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301912 SetUnionArrayFromMatrix(result, resultArray);
1913 break;
1914 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301915
Olli Etuahof119a262016-08-19 15:54:22 +03001916 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301917 {
Olli Etuahof119a262016-08-19 15:54:22 +03001918 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301919 unsigned int size = getType().getNominalSize();
1920 ASSERT(size >= 2 && size <= 4);
1921 resultArray = new TConstantUnion();
1922 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1923 break;
1924 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301925
Olli Etuahof119a262016-08-19 15:54:22 +03001926 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301927 {
Olli Etuahof119a262016-08-19 15:54:22 +03001928 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301929 unsigned int size = getType().getNominalSize();
1930 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001931 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301932 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1933 SetUnionArrayFromMatrix(result, resultArray);
1934 break;
1935 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301936
Olli Etuahof119a262016-08-19 15:54:22 +03001937 case EOpPackSnorm2x16:
1938 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301939 ASSERT(getType().getNominalSize() == 2);
1940 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001941 resultArray->setUConst(
1942 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301943 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301944
Olli Etuahof119a262016-08-19 15:54:22 +03001945 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301946 {
Olli Etuahof119a262016-08-19 15:54:22 +03001947 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301948 resultArray = new TConstantUnion[2];
1949 float f1, f2;
1950 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1951 resultArray[0].setFConst(f1);
1952 resultArray[1].setFConst(f2);
1953 break;
1954 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301955
Olli Etuahof119a262016-08-19 15:54:22 +03001956 case EOpPackUnorm2x16:
1957 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301958 ASSERT(getType().getNominalSize() == 2);
1959 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001960 resultArray->setUConst(
1961 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301962 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301963
Olli Etuahof119a262016-08-19 15:54:22 +03001964 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301965 {
Olli Etuahof119a262016-08-19 15:54:22 +03001966 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301967 resultArray = new TConstantUnion[2];
1968 float f1, f2;
1969 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1970 resultArray[0].setFConst(f1);
1971 resultArray[1].setFConst(f2);
1972 break;
1973 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301974
Olli Etuahof119a262016-08-19 15:54:22 +03001975 case EOpPackHalf2x16:
1976 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301977 ASSERT(getType().getNominalSize() == 2);
1978 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001979 resultArray->setUConst(
1980 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301981 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301982
Olli Etuahof119a262016-08-19 15:54:22 +03001983 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301984 {
Olli Etuahof119a262016-08-19 15:54:22 +03001985 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301986 resultArray = new TConstantUnion[2];
1987 float f1, f2;
1988 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1989 resultArray[0].setFConst(f1);
1990 resultArray[1].setFConst(f2);
1991 break;
1992 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301993
Olli Etuaho25aef452017-01-29 16:15:44 -08001994 case EOpPackUnorm4x8:
1995 {
1996 ASSERT(getType().getBasicType() == EbtFloat);
1997 resultArray = new TConstantUnion();
1998 resultArray->setUConst(
1999 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2000 operandArray[2].getFConst(), operandArray[3].getFConst()));
2001 break;
2002 }
2003 case EOpPackSnorm4x8:
2004 {
2005 ASSERT(getType().getBasicType() == EbtFloat);
2006 resultArray = new TConstantUnion();
2007 resultArray->setUConst(
2008 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2009 operandArray[2].getFConst(), operandArray[3].getFConst()));
2010 break;
2011 }
2012 case EOpUnpackUnorm4x8:
2013 {
2014 ASSERT(getType().getBasicType() == EbtUInt);
2015 resultArray = new TConstantUnion[4];
2016 float f[4];
2017 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2018 for (size_t i = 0; i < 4; ++i)
2019 {
2020 resultArray[i].setFConst(f[i]);
2021 }
2022 break;
2023 }
2024 case EOpUnpackSnorm4x8:
2025 {
2026 ASSERT(getType().getBasicType() == EbtUInt);
2027 resultArray = new TConstantUnion[4];
2028 float f[4];
2029 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2030 for (size_t i = 0; i < 4; ++i)
2031 {
2032 resultArray[i].setFConst(f[i]);
2033 }
2034 break;
2035 }
2036
Olli Etuahof119a262016-08-19 15:54:22 +03002037 default:
2038 UNREACHABLE();
2039 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302040 }
2041
2042 return resultArray;
2043}
2044
Olli Etuahof119a262016-08-19 15:54:22 +03002045TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2046 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302047{
Olli Etuahof119a262016-08-19 15:54:22 +03002048 // Do unary operations where each component of the result is computed based on the corresponding
2049 // component of the operand. Also folds normalize, though the divisor in that case takes all
2050 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302051
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002052 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002053 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002054
2055 size_t objectSize = getType().getObjectSize();
2056
Arun Patoleab2b9a22015-07-06 18:27:56 +05302057 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2058 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302059 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002060 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302061 {
Olli Etuahof119a262016-08-19 15:54:22 +03002062 case EOpNegative:
2063 switch (getType().getBasicType())
2064 {
2065 case EbtFloat:
2066 resultArray[i].setFConst(-operandArray[i].getFConst());
2067 break;
2068 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002069 if (operandArray[i] == std::numeric_limits<int>::min())
2070 {
2071 // The minimum representable integer doesn't have a positive
2072 // counterpart, rather the negation overflows and in ESSL is supposed to
2073 // wrap back to the minimum representable integer. Make sure that we
2074 // don't actually let the negation overflow, which has undefined
2075 // behavior in C++.
2076 resultArray[i].setIConst(std::numeric_limits<int>::min());
2077 }
2078 else
2079 {
2080 resultArray[i].setIConst(-operandArray[i].getIConst());
2081 }
Olli Etuahof119a262016-08-19 15:54:22 +03002082 break;
2083 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002084 if (operandArray[i] == 0x80000000u)
2085 {
2086 resultArray[i].setUConst(0x80000000u);
2087 }
2088 else
2089 {
2090 resultArray[i].setUConst(static_cast<unsigned int>(
2091 -static_cast<int>(operandArray[i].getUConst())));
2092 }
Olli Etuahof119a262016-08-19 15:54:22 +03002093 break;
2094 default:
2095 UNREACHABLE();
2096 return nullptr;
2097 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302098 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302099
Olli Etuahof119a262016-08-19 15:54:22 +03002100 case EOpPositive:
2101 switch (getType().getBasicType())
2102 {
2103 case EbtFloat:
2104 resultArray[i].setFConst(operandArray[i].getFConst());
2105 break;
2106 case EbtInt:
2107 resultArray[i].setIConst(operandArray[i].getIConst());
2108 break;
2109 case EbtUInt:
2110 resultArray[i].setUConst(static_cast<unsigned int>(
2111 static_cast<int>(operandArray[i].getUConst())));
2112 break;
2113 default:
2114 UNREACHABLE();
2115 return nullptr;
2116 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302117 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302118
Olli Etuahof119a262016-08-19 15:54:22 +03002119 case EOpLogicalNot:
2120 switch (getType().getBasicType())
2121 {
2122 case EbtBool:
2123 resultArray[i].setBConst(!operandArray[i].getBConst());
2124 break;
2125 default:
2126 UNREACHABLE();
2127 return nullptr;
2128 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302129 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302130
Olli Etuahof119a262016-08-19 15:54:22 +03002131 case EOpBitwiseNot:
2132 switch (getType().getBasicType())
2133 {
2134 case EbtInt:
2135 resultArray[i].setIConst(~operandArray[i].getIConst());
2136 break;
2137 case EbtUInt:
2138 resultArray[i].setUConst(~operandArray[i].getUConst());
2139 break;
2140 default:
2141 UNREACHABLE();
2142 return nullptr;
2143 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302144 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302145
Olli Etuahof119a262016-08-19 15:54:22 +03002146 case EOpRadians:
2147 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302148 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2149 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302150
Olli Etuahof119a262016-08-19 15:54:22 +03002151 case EOpDegrees:
2152 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302153 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2154 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302155
Olli Etuahof119a262016-08-19 15:54:22 +03002156 case EOpSin:
2157 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302158 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302159
Olli Etuahof119a262016-08-19 15:54:22 +03002160 case EOpCos:
2161 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2162 break;
2163
2164 case EOpTan:
2165 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2166 break;
2167
2168 case EOpAsin:
2169 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2170 // 0.
2171 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2172 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2173 diagnostics, &resultArray[i]);
2174 else
2175 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2176 break;
2177
2178 case EOpAcos:
2179 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2180 // 0.
2181 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2182 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2183 diagnostics, &resultArray[i]);
2184 else
2185 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2186 break;
2187
2188 case EOpAtan:
2189 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2190 break;
2191
2192 case EOpSinh:
2193 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2194 break;
2195
2196 case EOpCosh:
2197 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2198 break;
2199
2200 case EOpTanh:
2201 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2202 break;
2203
2204 case EOpAsinh:
2205 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2206 break;
2207
2208 case EOpAcosh:
2209 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2210 if (operandArray[i].getFConst() < 1.0f)
2211 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2212 diagnostics, &resultArray[i]);
2213 else
2214 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2215 break;
2216
2217 case EOpAtanh:
2218 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2219 // 0.
2220 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2221 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2222 diagnostics, &resultArray[i]);
2223 else
2224 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2225 break;
2226
2227 case EOpAbs:
2228 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302229 {
Olli Etuahof119a262016-08-19 15:54:22 +03002230 case EbtFloat:
2231 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2232 break;
2233 case EbtInt:
2234 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2235 break;
2236 default:
2237 UNREACHABLE();
2238 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302239 }
2240 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002241
2242 case EOpSign:
2243 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302244 {
Olli Etuahof119a262016-08-19 15:54:22 +03002245 case EbtFloat:
2246 {
2247 float fConst = operandArray[i].getFConst();
2248 float fResult = 0.0f;
2249 if (fConst > 0.0f)
2250 fResult = 1.0f;
2251 else if (fConst < 0.0f)
2252 fResult = -1.0f;
2253 resultArray[i].setFConst(fResult);
2254 break;
2255 }
2256 case EbtInt:
2257 {
2258 int iConst = operandArray[i].getIConst();
2259 int iResult = 0;
2260 if (iConst > 0)
2261 iResult = 1;
2262 else if (iConst < 0)
2263 iResult = -1;
2264 resultArray[i].setIConst(iResult);
2265 break;
2266 }
2267 default:
2268 UNREACHABLE();
2269 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302270 }
2271 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302272
Olli Etuahof119a262016-08-19 15:54:22 +03002273 case EOpFloor:
2274 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2275 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302276
Olli Etuahof119a262016-08-19 15:54:22 +03002277 case EOpTrunc:
2278 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2279 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302280
Olli Etuahof119a262016-08-19 15:54:22 +03002281 case EOpRound:
2282 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2283 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302284
Olli Etuahof119a262016-08-19 15:54:22 +03002285 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302286 {
Olli Etuahof119a262016-08-19 15:54:22 +03002287 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302288 float x = operandArray[i].getFConst();
2289 float result;
2290 float fractPart = modff(x, &result);
2291 if (fabsf(fractPart) == 0.5f)
2292 result = 2.0f * roundf(x / 2.0f);
2293 else
2294 result = roundf(x);
2295 resultArray[i].setFConst(result);
2296 break;
2297 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302298
Olli Etuahof119a262016-08-19 15:54:22 +03002299 case EOpCeil:
2300 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2301 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302302
Olli Etuahof119a262016-08-19 15:54:22 +03002303 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302304 {
Olli Etuahof119a262016-08-19 15:54:22 +03002305 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302306 float x = operandArray[i].getFConst();
2307 resultArray[i].setFConst(x - floorf(x));
2308 break;
2309 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302310
Olli Etuahof119a262016-08-19 15:54:22 +03002311 case EOpIsNan:
2312 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302313 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2314 break;
Arun Patole551279e2015-07-07 18:18:23 +05302315
Olli Etuahof119a262016-08-19 15:54:22 +03002316 case EOpIsInf:
2317 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302318 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2319 break;
Arun Patole551279e2015-07-07 18:18:23 +05302320
Olli Etuahof119a262016-08-19 15:54:22 +03002321 case EOpFloatBitsToInt:
2322 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302323 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2324 break;
Arun Patole551279e2015-07-07 18:18:23 +05302325
Olli Etuahof119a262016-08-19 15:54:22 +03002326 case EOpFloatBitsToUint:
2327 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302328 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2329 break;
Arun Patole551279e2015-07-07 18:18:23 +05302330
Olli Etuahof119a262016-08-19 15:54:22 +03002331 case EOpIntBitsToFloat:
2332 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302333 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2334 break;
Arun Patole551279e2015-07-07 18:18:23 +05302335
Olli Etuahof119a262016-08-19 15:54:22 +03002336 case EOpUintBitsToFloat:
2337 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302338 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2339 break;
Arun Patole551279e2015-07-07 18:18:23 +05302340
Olli Etuahof119a262016-08-19 15:54:22 +03002341 case EOpExp:
2342 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2343 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302344
Olli Etuahof119a262016-08-19 15:54:22 +03002345 case EOpLog:
2346 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2347 if (operandArray[i].getFConst() <= 0.0f)
2348 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2349 diagnostics, &resultArray[i]);
2350 else
2351 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2352 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302353
Olli Etuahof119a262016-08-19 15:54:22 +03002354 case EOpExp2:
2355 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2356 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302357
Olli Etuahof119a262016-08-19 15:54:22 +03002358 case EOpLog2:
2359 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2360 // And log2f is not available on some plarforms like old android, so just using
2361 // log(x)/log(2) here.
2362 if (operandArray[i].getFConst() <= 0.0f)
2363 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2364 diagnostics, &resultArray[i]);
2365 else
2366 {
2367 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2368 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2369 }
2370 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302371
Olli Etuahof119a262016-08-19 15:54:22 +03002372 case EOpSqrt:
2373 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2374 if (operandArray[i].getFConst() < 0.0f)
2375 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2376 diagnostics, &resultArray[i]);
2377 else
2378 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2379 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302380
Olli Etuahof119a262016-08-19 15:54:22 +03002381 case EOpInverseSqrt:
2382 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2383 // so getting the square root first using builtin function sqrt() and then taking
2384 // its inverse.
2385 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2386 // result to 0.
2387 if (operandArray[i].getFConst() <= 0.0f)
2388 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2389 diagnostics, &resultArray[i]);
2390 else
2391 {
2392 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2393 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2394 }
2395 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302396
Olli Etuahod68924e2017-01-02 17:34:40 +00002397 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002398 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302399 resultArray[i].setBConst(!operandArray[i].getBConst());
2400 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302401
Olli Etuahof119a262016-08-19 15:54:22 +03002402 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302403 {
Olli Etuahof119a262016-08-19 15:54:22 +03002404 ASSERT(getType().getBasicType() == EbtFloat);
2405 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302406 float length = VectorLength(operandArray, objectSize);
2407 if (length)
2408 resultArray[i].setFConst(x / length);
2409 else
Olli Etuahof119a262016-08-19 15:54:22 +03002410 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2411 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302412 break;
2413 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002414 case EOpBitfieldReverse:
2415 {
2416 uint32_t value;
2417 if (getType().getBasicType() == EbtInt)
2418 {
2419 value = static_cast<uint32_t>(operandArray[i].getIConst());
2420 }
2421 else
2422 {
2423 ASSERT(getType().getBasicType() == EbtUInt);
2424 value = operandArray[i].getUConst();
2425 }
2426 uint32_t result = gl::BitfieldReverse(value);
2427 if (getType().getBasicType() == EbtInt)
2428 {
2429 resultArray[i].setIConst(static_cast<int32_t>(result));
2430 }
2431 else
2432 {
2433 resultArray[i].setUConst(result);
2434 }
2435 break;
2436 }
2437 case EOpBitCount:
2438 {
2439 uint32_t value;
2440 if (getType().getBasicType() == EbtInt)
2441 {
2442 value = static_cast<uint32_t>(operandArray[i].getIConst());
2443 }
2444 else
2445 {
2446 ASSERT(getType().getBasicType() == EbtUInt);
2447 value = operandArray[i].getUConst();
2448 }
2449 int result = gl::BitCount(value);
2450 resultArray[i].setIConst(result);
2451 break;
2452 }
2453 case EOpFindLSB:
2454 {
2455 uint32_t value;
2456 if (getType().getBasicType() == EbtInt)
2457 {
2458 value = static_cast<uint32_t>(operandArray[i].getIConst());
2459 }
2460 else
2461 {
2462 ASSERT(getType().getBasicType() == EbtUInt);
2463 value = operandArray[i].getUConst();
2464 }
2465 resultArray[i].setIConst(gl::FindLSB(value));
2466 break;
2467 }
2468 case EOpFindMSB:
2469 {
2470 uint32_t value;
2471 if (getType().getBasicType() == EbtInt)
2472 {
2473 int intValue = operandArray[i].getIConst();
2474 value = static_cast<uint32_t>(intValue);
2475 if (intValue < 0)
2476 {
2477 // Look for zero instead of one in value. This also handles the intValue ==
2478 // -1 special case, where the return value needs to be -1.
2479 value = ~value;
2480 }
2481 }
2482 else
2483 {
2484 ASSERT(getType().getBasicType() == EbtUInt);
2485 value = operandArray[i].getUConst();
2486 }
2487 resultArray[i].setIConst(gl::FindMSB(value));
2488 break;
2489 }
Olli Etuahof119a262016-08-19 15:54:22 +03002490 case EOpDFdx:
2491 case EOpDFdy:
2492 case EOpFwidth:
2493 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302494 // Derivatives of constant arguments should be 0.
2495 resultArray[i].setFConst(0.0f);
2496 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302497
Olli Etuahof119a262016-08-19 15:54:22 +03002498 default:
2499 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302500 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302501 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002502
Arun Patoleab2b9a22015-07-06 18:27:56 +05302503 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002504}
2505
Olli Etuahof119a262016-08-19 15:54:22 +03002506void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2507 FloatTypeUnaryFunc builtinFunc,
2508 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302509{
2510 ASSERT(builtinFunc);
2511
Olli Etuahof119a262016-08-19 15:54:22 +03002512 ASSERT(getType().getBasicType() == EbtFloat);
2513 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302514}
2515
Jamie Madillb1a85f42014-08-19 15:23:24 -04002516// static
Olli Etuahof119a262016-08-19 15:54:22 +03002517TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002518{
2519 ASSERT(aggregate->getSequence()->size() > 0u);
2520 size_t resultSize = aggregate->getType().getObjectSize();
2521 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2522 TBasicType basicType = aggregate->getBasicType();
2523
2524 size_t resultIndex = 0u;
2525
2526 if (aggregate->getSequence()->size() == 1u)
2527 {
2528 TIntermNode *argument = aggregate->getSequence()->front();
2529 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2530 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2531 // Check the special case of constructing a matrix diagonal from a single scalar,
2532 // or a vector from a single scalar.
2533 if (argumentConstant->getType().getObjectSize() == 1u)
2534 {
2535 if (aggregate->isMatrix())
2536 {
2537 int resultCols = aggregate->getType().getCols();
2538 int resultRows = aggregate->getType().getRows();
2539 for (int col = 0; col < resultCols; ++col)
2540 {
2541 for (int row = 0; row < resultRows; ++row)
2542 {
2543 if (col == row)
2544 {
2545 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2546 }
2547 else
2548 {
2549 resultArray[resultIndex].setFConst(0.0f);
2550 }
2551 ++resultIndex;
2552 }
2553 }
2554 }
2555 else
2556 {
2557 while (resultIndex < resultSize)
2558 {
2559 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2560 ++resultIndex;
2561 }
2562 }
2563 ASSERT(resultIndex == resultSize);
2564 return resultArray;
2565 }
2566 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2567 {
2568 // The special case of constructing a matrix from a matrix.
2569 int argumentCols = argumentConstant->getType().getCols();
2570 int argumentRows = argumentConstant->getType().getRows();
2571 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002572 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002573 for (int col = 0; col < resultCols; ++col)
2574 {
2575 for (int row = 0; row < resultRows; ++row)
2576 {
2577 if (col < argumentCols && row < argumentRows)
2578 {
2579 resultArray[resultIndex].cast(basicType,
2580 argumentUnionArray[col * argumentRows + row]);
2581 }
2582 else if (col == row)
2583 {
2584 resultArray[resultIndex].setFConst(1.0f);
2585 }
2586 else
2587 {
2588 resultArray[resultIndex].setFConst(0.0f);
2589 }
2590 ++resultIndex;
2591 }
2592 }
2593 ASSERT(resultIndex == resultSize);
2594 return resultArray;
2595 }
2596 }
2597
2598 for (TIntermNode *&argument : *aggregate->getSequence())
2599 {
2600 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2601 size_t argumentSize = argumentConstant->getType().getObjectSize();
2602 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2603 for (size_t i = 0u; i < argumentSize; ++i)
2604 {
2605 if (resultIndex >= resultSize)
2606 break;
2607 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2608 ++resultIndex;
2609 }
2610 }
2611 ASSERT(resultIndex == resultSize);
2612 return resultArray;
2613}
2614
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002615bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2616{
2617 switch (op)
2618 {
2619 case EOpAtan:
2620 case EOpPow:
2621 case EOpMod:
2622 case EOpMin:
2623 case EOpMax:
2624 case EOpClamp:
2625 case EOpMix:
2626 case EOpStep:
2627 case EOpSmoothStep:
2628 case EOpLdexp:
2629 case EOpMulMatrixComponentWise:
2630 case EOpOuterProduct:
2631 case EOpEqualComponentWise:
2632 case EOpNotEqualComponentWise:
2633 case EOpLessThanComponentWise:
2634 case EOpLessThanEqualComponentWise:
2635 case EOpGreaterThanComponentWise:
2636 case EOpGreaterThanEqualComponentWise:
2637 case EOpDistance:
2638 case EOpDot:
2639 case EOpCross:
2640 case EOpFaceforward:
2641 case EOpReflect:
2642 case EOpRefract:
2643 case EOpBitfieldExtract:
2644 case EOpBitfieldInsert:
2645 return true;
2646 default:
2647 return false;
2648 }
2649}
2650
Olli Etuaho1d122782015-11-06 15:35:17 +02002651// static
Olli Etuahof119a262016-08-19 15:54:22 +03002652TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2653 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302654{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002655 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002656 TIntermSequence *arguments = aggregate->getSequence();
2657 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2658 std::vector<const TConstantUnion *> unionArrays(argsCount);
2659 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002660 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302661 TBasicType basicType = EbtVoid;
2662 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002663 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302664 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002665 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2666 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302667
2668 if (i == 0)
2669 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002670 basicType = argConstant->getType().getBasicType();
2671 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302672 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002673 unionArrays[i] = argConstant->getUnionArrayPointer();
2674 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002675 if (objectSizes[i] > maxObjectSize)
2676 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302677 }
2678
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002679 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302680 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002681 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302682 if (objectSizes[i] != maxObjectSize)
2683 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2684 }
Arun Patole274f0702015-05-05 13:33:30 +05302685
Olli Etuahob43846e2015-06-02 18:18:57 +03002686 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002687
2688 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302689 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002690 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302691 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002692 ASSERT(basicType == EbtFloat);
2693 resultArray = new TConstantUnion[maxObjectSize];
2694 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302695 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002696 float y = unionArrays[0][i].getFConst();
2697 float x = unionArrays[1][i].getFConst();
2698 // Results are undefined if x and y are both 0.
2699 if (x == 0.0f && y == 0.0f)
2700 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2701 else
2702 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302703 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002704 break;
2705 }
Arun Patolebf790422015-05-18 17:53:04 +05302706
Olli Etuaho51182ab2017-01-22 00:12:29 +00002707 case EOpPow:
2708 {
2709 ASSERT(basicType == EbtFloat);
2710 resultArray = new TConstantUnion[maxObjectSize];
2711 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302712 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002713 float x = unionArrays[0][i].getFConst();
2714 float y = unionArrays[1][i].getFConst();
2715 // Results are undefined if x < 0.
2716 // Results are undefined if x = 0 and y <= 0.
2717 if (x < 0.0f)
2718 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2719 else if (x == 0.0f && y <= 0.0f)
2720 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2721 else
2722 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302723 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002724 break;
2725 }
Arun Patolebf790422015-05-18 17:53:04 +05302726
Olli Etuaho51182ab2017-01-22 00:12:29 +00002727 case EOpMod:
2728 {
2729 ASSERT(basicType == EbtFloat);
2730 resultArray = new TConstantUnion[maxObjectSize];
2731 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302732 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002733 float x = unionArrays[0][i].getFConst();
2734 float y = unionArrays[1][i].getFConst();
2735 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302736 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002737 break;
2738 }
Arun Patolebf790422015-05-18 17:53:04 +05302739
Olli Etuaho51182ab2017-01-22 00:12:29 +00002740 case EOpMin:
2741 {
2742 resultArray = new TConstantUnion[maxObjectSize];
2743 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302744 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002745 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302746 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002747 case EbtFloat:
2748 resultArray[i].setFConst(
2749 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2750 break;
2751 case EbtInt:
2752 resultArray[i].setIConst(
2753 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2754 break;
2755 case EbtUInt:
2756 resultArray[i].setUConst(
2757 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2758 break;
2759 default:
2760 UNREACHABLE();
2761 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302762 }
2763 }
2764 break;
Arun Patole274f0702015-05-05 13:33:30 +05302765 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002766
2767 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302768 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002769 resultArray = new TConstantUnion[maxObjectSize];
2770 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302771 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002772 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302773 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002774 case EbtFloat:
2775 resultArray[i].setFConst(
2776 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2777 break;
2778 case EbtInt:
2779 resultArray[i].setIConst(
2780 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2781 break;
2782 case EbtUInt:
2783 resultArray[i].setUConst(
2784 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2785 break;
2786 default:
2787 UNREACHABLE();
2788 break;
Arun Patole274f0702015-05-05 13:33:30 +05302789 }
2790 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002791 break;
Arun Patole274f0702015-05-05 13:33:30 +05302792 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002793
2794 case EOpStep:
2795 {
2796 ASSERT(basicType == EbtFloat);
2797 resultArray = new TConstantUnion[maxObjectSize];
2798 for (size_t i = 0; i < maxObjectSize; i++)
2799 resultArray[i].setFConst(
2800 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2801 break;
2802 }
2803
2804 case EOpLessThanComponentWise:
2805 {
2806 resultArray = new TConstantUnion[maxObjectSize];
2807 for (size_t i = 0; i < maxObjectSize; i++)
2808 {
2809 switch (basicType)
2810 {
2811 case EbtFloat:
2812 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2813 unionArrays[1][i].getFConst());
2814 break;
2815 case EbtInt:
2816 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2817 unionArrays[1][i].getIConst());
2818 break;
2819 case EbtUInt:
2820 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2821 unionArrays[1][i].getUConst());
2822 break;
2823 default:
2824 UNREACHABLE();
2825 break;
2826 }
2827 }
2828 break;
2829 }
2830
2831 case EOpLessThanEqualComponentWise:
2832 {
2833 resultArray = new TConstantUnion[maxObjectSize];
2834 for (size_t i = 0; i < maxObjectSize; i++)
2835 {
2836 switch (basicType)
2837 {
2838 case EbtFloat:
2839 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2840 unionArrays[1][i].getFConst());
2841 break;
2842 case EbtInt:
2843 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2844 unionArrays[1][i].getIConst());
2845 break;
2846 case EbtUInt:
2847 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2848 unionArrays[1][i].getUConst());
2849 break;
2850 default:
2851 UNREACHABLE();
2852 break;
2853 }
2854 }
2855 break;
2856 }
2857
2858 case EOpGreaterThanComponentWise:
2859 {
2860 resultArray = new TConstantUnion[maxObjectSize];
2861 for (size_t i = 0; i < maxObjectSize; i++)
2862 {
2863 switch (basicType)
2864 {
2865 case EbtFloat:
2866 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2867 unionArrays[1][i].getFConst());
2868 break;
2869 case EbtInt:
2870 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2871 unionArrays[1][i].getIConst());
2872 break;
2873 case EbtUInt:
2874 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2875 unionArrays[1][i].getUConst());
2876 break;
2877 default:
2878 UNREACHABLE();
2879 break;
2880 }
2881 }
2882 break;
2883 }
2884 case EOpGreaterThanEqualComponentWise:
2885 {
2886 resultArray = new TConstantUnion[maxObjectSize];
2887 for (size_t i = 0; i < maxObjectSize; i++)
2888 {
2889 switch (basicType)
2890 {
2891 case EbtFloat:
2892 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2893 unionArrays[1][i].getFConst());
2894 break;
2895 case EbtInt:
2896 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2897 unionArrays[1][i].getIConst());
2898 break;
2899 case EbtUInt:
2900 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2901 unionArrays[1][i].getUConst());
2902 break;
2903 default:
2904 UNREACHABLE();
2905 break;
2906 }
2907 }
2908 }
2909 break;
2910
2911 case EOpEqualComponentWise:
2912 {
2913 resultArray = new TConstantUnion[maxObjectSize];
2914 for (size_t i = 0; i < maxObjectSize; i++)
2915 {
2916 switch (basicType)
2917 {
2918 case EbtFloat:
2919 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2920 unionArrays[1][i].getFConst());
2921 break;
2922 case EbtInt:
2923 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2924 unionArrays[1][i].getIConst());
2925 break;
2926 case EbtUInt:
2927 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2928 unionArrays[1][i].getUConst());
2929 break;
2930 case EbtBool:
2931 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2932 unionArrays[1][i].getBConst());
2933 break;
2934 default:
2935 UNREACHABLE();
2936 break;
2937 }
2938 }
2939 break;
2940 }
2941
2942 case EOpNotEqualComponentWise:
2943 {
2944 resultArray = new TConstantUnion[maxObjectSize];
2945 for (size_t i = 0; i < maxObjectSize; i++)
2946 {
2947 switch (basicType)
2948 {
2949 case EbtFloat:
2950 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2951 unionArrays[1][i].getFConst());
2952 break;
2953 case EbtInt:
2954 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2955 unionArrays[1][i].getIConst());
2956 break;
2957 case EbtUInt:
2958 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2959 unionArrays[1][i].getUConst());
2960 break;
2961 case EbtBool:
2962 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2963 unionArrays[1][i].getBConst());
2964 break;
2965 default:
2966 UNREACHABLE();
2967 break;
2968 }
2969 }
2970 break;
2971 }
2972
2973 case EOpDistance:
2974 {
2975 ASSERT(basicType == EbtFloat);
2976 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2977 resultArray = new TConstantUnion();
2978 for (size_t i = 0; i < maxObjectSize; i++)
2979 {
2980 float x = unionArrays[0][i].getFConst();
2981 float y = unionArrays[1][i].getFConst();
2982 distanceArray[i].setFConst(x - y);
2983 }
2984 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2985 break;
2986 }
2987
2988 case EOpDot:
2989 ASSERT(basicType == EbtFloat);
2990 resultArray = new TConstantUnion();
2991 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2992 break;
2993
2994 case EOpCross:
2995 {
2996 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2997 resultArray = new TConstantUnion[maxObjectSize];
2998 float x0 = unionArrays[0][0].getFConst();
2999 float x1 = unionArrays[0][1].getFConst();
3000 float x2 = unionArrays[0][2].getFConst();
3001 float y0 = unionArrays[1][0].getFConst();
3002 float y1 = unionArrays[1][1].getFConst();
3003 float y2 = unionArrays[1][2].getFConst();
3004 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3005 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3006 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3007 break;
3008 }
3009
3010 case EOpReflect:
3011 {
3012 ASSERT(basicType == EbtFloat);
3013 // genType reflect (genType I, genType N) :
3014 // For the incident vector I and surface orientation N, returns the reflection
3015 // direction:
3016 // I - 2 * dot(N, I) * N.
3017 resultArray = new TConstantUnion[maxObjectSize];
3018 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3019 for (size_t i = 0; i < maxObjectSize; i++)
3020 {
3021 float result = unionArrays[0][i].getFConst() -
3022 2.0f * dotProduct * unionArrays[1][i].getFConst();
3023 resultArray[i].setFConst(result);
3024 }
3025 break;
3026 }
3027
3028 case EOpMulMatrixComponentWise:
3029 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003030 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3031 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003032 // Perform component-wise matrix multiplication.
3033 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003034 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003035 angle::Matrix<float> result =
3036 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3037 SetUnionArrayFromMatrix(result, resultArray);
3038 break;
3039 }
3040
3041 case EOpOuterProduct:
3042 {
3043 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003044 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3045 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003046 resultArray = new TConstantUnion[numRows * numCols];
3047 angle::Matrix<float> result =
3048 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3049 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3050 SetUnionArrayFromMatrix(result, resultArray);
3051 break;
3052 }
3053
3054 case EOpClamp:
3055 {
3056 resultArray = new TConstantUnion[maxObjectSize];
3057 for (size_t i = 0; i < maxObjectSize; i++)
3058 {
3059 switch (basicType)
3060 {
3061 case EbtFloat:
3062 {
3063 float x = unionArrays[0][i].getFConst();
3064 float min = unionArrays[1][i].getFConst();
3065 float max = unionArrays[2][i].getFConst();
3066 // Results are undefined if min > max.
3067 if (min > max)
3068 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3069 &resultArray[i]);
3070 else
3071 resultArray[i].setFConst(gl::clamp(x, min, max));
3072 break;
3073 }
3074
3075 case EbtInt:
3076 {
3077 int x = unionArrays[0][i].getIConst();
3078 int min = unionArrays[1][i].getIConst();
3079 int max = unionArrays[2][i].getIConst();
3080 // Results are undefined if min > max.
3081 if (min > max)
3082 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3083 &resultArray[i]);
3084 else
3085 resultArray[i].setIConst(gl::clamp(x, min, max));
3086 break;
3087 }
3088 case EbtUInt:
3089 {
3090 unsigned int x = unionArrays[0][i].getUConst();
3091 unsigned int min = unionArrays[1][i].getUConst();
3092 unsigned int max = unionArrays[2][i].getUConst();
3093 // Results are undefined if min > max.
3094 if (min > max)
3095 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3096 &resultArray[i]);
3097 else
3098 resultArray[i].setUConst(gl::clamp(x, min, max));
3099 break;
3100 }
3101 default:
3102 UNREACHABLE();
3103 break;
3104 }
3105 }
3106 break;
3107 }
3108
3109 case EOpMix:
3110 {
3111 ASSERT(basicType == EbtFloat);
3112 resultArray = new TConstantUnion[maxObjectSize];
3113 for (size_t i = 0; i < maxObjectSize; i++)
3114 {
3115 float x = unionArrays[0][i].getFConst();
3116 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003117 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003118 if (type == EbtFloat)
3119 {
3120 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3121 float a = unionArrays[2][i].getFConst();
3122 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3123 }
3124 else // 3rd parameter is EbtBool
3125 {
3126 ASSERT(type == EbtBool);
3127 // Selects which vector each returned component comes from.
3128 // For a component of a that is false, the corresponding component of x is
3129 // returned.
3130 // For a component of a that is true, the corresponding component of y is
3131 // returned.
3132 bool a = unionArrays[2][i].getBConst();
3133 resultArray[i].setFConst(a ? y : x);
3134 }
3135 }
3136 break;
3137 }
3138
3139 case EOpSmoothStep:
3140 {
3141 ASSERT(basicType == EbtFloat);
3142 resultArray = new TConstantUnion[maxObjectSize];
3143 for (size_t i = 0; i < maxObjectSize; i++)
3144 {
3145 float edge0 = unionArrays[0][i].getFConst();
3146 float edge1 = unionArrays[1][i].getFConst();
3147 float x = unionArrays[2][i].getFConst();
3148 // Results are undefined if edge0 >= edge1.
3149 if (edge0 >= edge1)
3150 {
3151 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3152 }
3153 else
3154 {
3155 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3156 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3157 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3158 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3159 }
3160 }
3161 break;
3162 }
3163
Olli Etuaho74da73f2017-02-01 15:37:48 +00003164 case EOpLdexp:
3165 {
3166 resultArray = new TConstantUnion[maxObjectSize];
3167 for (size_t i = 0; i < maxObjectSize; i++)
3168 {
3169 float x = unionArrays[0][i].getFConst();
3170 int exp = unionArrays[1][i].getIConst();
3171 if (exp > 128)
3172 {
3173 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3174 }
3175 else
3176 {
3177 resultArray[i].setFConst(gl::Ldexp(x, exp));
3178 }
3179 }
3180 break;
3181 }
3182
Jamie Madille72595b2017-06-06 15:12:26 -04003183 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003184 {
3185 ASSERT(basicType == EbtFloat);
3186 // genType faceforward(genType N, genType I, genType Nref) :
3187 // If dot(Nref, I) < 0 return N, otherwise return -N.
3188 resultArray = new TConstantUnion[maxObjectSize];
3189 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3190 for (size_t i = 0; i < maxObjectSize; i++)
3191 {
3192 if (dotProduct < 0)
3193 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3194 else
3195 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3196 }
3197 break;
3198 }
3199
3200 case EOpRefract:
3201 {
3202 ASSERT(basicType == EbtFloat);
3203 // genType refract(genType I, genType N, float eta) :
3204 // For the incident vector I and surface normal N, and the ratio of indices of
3205 // refraction eta,
3206 // return the refraction vector. The result is computed by
3207 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3208 // if (k < 0.0)
3209 // return genType(0.0)
3210 // else
3211 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3212 resultArray = new TConstantUnion[maxObjectSize];
3213 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3214 for (size_t i = 0; i < maxObjectSize; i++)
3215 {
3216 float eta = unionArrays[2][i].getFConst();
3217 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3218 if (k < 0.0f)
3219 resultArray[i].setFConst(0.0f);
3220 else
3221 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3222 (eta * dotProduct + sqrtf(k)) *
3223 unionArrays[1][i].getFConst());
3224 }
3225 break;
3226 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003227 case EOpBitfieldExtract:
3228 {
3229 resultArray = new TConstantUnion[maxObjectSize];
3230 for (size_t i = 0; i < maxObjectSize; ++i)
3231 {
3232 int offset = unionArrays[1][0].getIConst();
3233 int bits = unionArrays[2][0].getIConst();
3234 if (bits == 0)
3235 {
3236 if (aggregate->getBasicType() == EbtInt)
3237 {
3238 resultArray[i].setIConst(0);
3239 }
3240 else
3241 {
3242 ASSERT(aggregate->getBasicType() == EbtUInt);
3243 resultArray[i].setUConst(0);
3244 }
3245 }
3246 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3247 {
3248 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3249 &resultArray[i]);
3250 }
3251 else
3252 {
3253 // bits can be 32 here, so we need to avoid bit shift overflow.
3254 uint32_t maskMsb = 1u << (bits - 1);
3255 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3256 if (aggregate->getBasicType() == EbtInt)
3257 {
3258 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3259 uint32_t resultUnsigned = (value & mask) >> offset;
3260 if ((resultUnsigned & maskMsb) != 0)
3261 {
3262 // The most significant bits (from bits+1 to the most significant bit)
3263 // should be set to 1.
3264 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3265 resultUnsigned |= higherBitsMask;
3266 }
3267 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3268 }
3269 else
3270 {
3271 ASSERT(aggregate->getBasicType() == EbtUInt);
3272 uint32_t value = unionArrays[0][i].getUConst();
3273 resultArray[i].setUConst((value & mask) >> offset);
3274 }
3275 }
3276 }
3277 break;
3278 }
3279 case EOpBitfieldInsert:
3280 {
3281 resultArray = new TConstantUnion[maxObjectSize];
3282 for (size_t i = 0; i < maxObjectSize; ++i)
3283 {
3284 int offset = unionArrays[2][0].getIConst();
3285 int bits = unionArrays[3][0].getIConst();
3286 if (bits == 0)
3287 {
3288 if (aggregate->getBasicType() == EbtInt)
3289 {
3290 int32_t base = unionArrays[0][i].getIConst();
3291 resultArray[i].setIConst(base);
3292 }
3293 else
3294 {
3295 ASSERT(aggregate->getBasicType() == EbtUInt);
3296 uint32_t base = unionArrays[0][i].getUConst();
3297 resultArray[i].setUConst(base);
3298 }
3299 }
3300 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3301 {
3302 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3303 &resultArray[i]);
3304 }
3305 else
3306 {
3307 // bits can be 32 here, so we need to avoid bit shift overflow.
3308 uint32_t maskMsb = 1u << (bits - 1);
3309 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3310 uint32_t baseMask = ~insertMask;
3311 if (aggregate->getBasicType() == EbtInt)
3312 {
3313 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3314 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3315 uint32_t resultUnsigned =
3316 (base & baseMask) | ((insert << offset) & insertMask);
3317 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3318 }
3319 else
3320 {
3321 ASSERT(aggregate->getBasicType() == EbtUInt);
3322 uint32_t base = unionArrays[0][i].getUConst();
3323 uint32_t insert = unionArrays[1][i].getUConst();
3324 resultArray[i].setUConst((base & baseMask) |
3325 ((insert << offset) & insertMask));
3326 }
3327 }
3328 }
3329 break;
3330 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003331
3332 default:
3333 UNREACHABLE();
3334 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303335 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003336 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303337}
3338
Jamie Madill45bcc782016-11-07 13:58:48 -05003339} // namespace sh