blob: 6f63f0e6ef9bef6ccc8d0b9ac36995a74d39c360 [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
Olli Etuahoae4dbf32017-12-08 20:49:00 +0100147TName::TName(const TString *name) : mName(name ? (*name) : ""), mIsInternal(false)
148{
149}
150
Olli Etuaho1bb85282017-12-14 13:39:53 +0200151TName::TName(const TSymbol *symbol)
152 : mName(*symbol->name()), mIsInternal(symbol->symbolType() == SymbolType::AngleInternal)
153{
154}
155
Jamie Madillb1a85f42014-08-19 15:23:24 -0400156////////////////////////////////////////////////////////////////
157//
158// Member functions of the nodes used for building the tree.
159//
160////////////////////////////////////////////////////////////////
161
Olli Etuahod2a67b92014-10-21 16:42:57 +0300162void TIntermTyped::setTypePreservePrecision(const TType &t)
163{
164 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500165 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300166 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
167 mType.setPrecision(precision);
168}
169
Jamie Madillb1a85f42014-08-19 15:23:24 -0400170#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500171 if (node == original) \
172 { \
173 node = static_cast<type *>(replacement); \
174 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400175 }
176
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500177bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400178{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300179 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400180 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
181 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
182 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100183 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400184 return false;
185}
186
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500187bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400188{
189 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
190 return false;
191}
192
Olli Etuahob6fa0432016-09-28 16:28:05 +0100193bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
194{
195 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
196 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
197 return false;
198}
199
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500200bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400201{
202 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
203 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
204 return false;
205}
206
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500207bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400208{
Olli Etuahoa2234302016-08-31 12:05:39 +0300209 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400210 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
211 return false;
212}
213
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000214bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
215{
216 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
217 return false;
218}
219
Olli Etuaho336b1472016-10-05 16:37:55 +0100220bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
221{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000222 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100223 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
224 return false;
225}
226
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500227bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400228{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100229 return replaceChildNodeInternal(original, replacement);
230}
231
232bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
233{
234 return replaceChildNodeInternal(original, replacement);
235}
236
Olli Etuaho16c745a2017-01-16 17:02:27 +0000237bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
238{
239 return replaceChildNodeInternal(original, replacement);
240}
241
Olli Etuaho13389b62016-10-16 11:48:18 +0100242bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
243{
244 return replaceChildNodeInternal(original, replacement);
245}
246
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100247bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
248{
249 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400250 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100251 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400252 }
253 return false;
254}
255
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100256bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
257 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300258{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100259 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300260 {
261 if (*it == original)
262 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100263 it = getSequence()->erase(it);
264 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300265 return true;
266 }
267 }
268 return false;
269}
270
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100271bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
272 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300273{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100274 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300275 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300276 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300277 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100278 auto it = getSequence()->begin() + position;
279 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300280 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300281}
282
Olli Etuaho195be942017-12-04 23:40:14 +0200283TIntermSymbol::TIntermSymbol(const TVariable *variable)
284 : TIntermTyped(variable->getType()), mId(variable->uniqueId()), mSymbol(variable->name())
285{
286 if (variable->symbolType() == SymbolType::AngleInternal)
287 {
288 mSymbol.setInternal(true);
289 }
290}
291
Olli Etuahofe486322017-03-21 09:30:54 +0000292TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
293 TIntermSequence *arguments)
294{
Olli Etuaho0c371002017-12-13 17:00:25 +0400295 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000296}
297
Olli Etuaho0c371002017-12-13 17:00:25 +0400298TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
299 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000300{
Olli Etuaho0c371002017-12-13 17:00:25 +0400301 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000302}
303
304TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
305 TIntermSequence *arguments)
306{
307 TIntermAggregate *callNode =
Olli Etuaho0c371002017-12-13 17:00:25 +0400308 new TIntermAggregate(&func, func.getReturnType(), EOpCallBuiltInFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000309 // 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 Etuaho0c371002017-12-13 17:00:25 +0400317 return new TIntermAggregate(nullptr, 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{
Olli Etuahofe486322017-03-21 09:30:54 +0000324 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400325 ASSERT(op != EOpCallInternalRawFunction); // Should use CreateRawFunctionCall
Olli Etuahofe486322017-03-21 09:30:54 +0000326 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400327 ASSERT(op != EOpConstruct); // Should use CreateConstructor
328 return new TIntermAggregate(nullptr, type, op, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000329}
330
Olli Etuaho0c371002017-12-13 17:00:25 +0400331TIntermAggregate::TIntermAggregate(const TFunction *func,
332 const TType &type,
333 TOperator op,
334 TIntermSequence *arguments)
335 : TIntermOperator(op),
336 mUseEmulatedFunction(false),
337 mGotPrecisionFromChildren(false),
338 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800339{
340 if (arguments != nullptr)
341 {
342 mArguments.swap(*arguments);
343 }
Olli Etuaho1bb85282017-12-14 13:39:53 +0200344 ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800345 setTypePrecisionAndQualifier(type);
346}
347
348void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
349{
350 setType(type);
351 mType.setQualifier(EvqTemporary);
352 if (!isFunctionCall())
353 {
354 if (isConstructor())
355 {
356 // Structs should not be precision qualified, the individual members may be.
357 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300358 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800359 {
360 setPrecisionFromChildren();
361 }
362 }
363 else
364 {
365 setPrecisionForBuiltInOp();
366 }
367 if (areChildrenConstQualified())
368 {
369 mType.setQualifier(EvqConst);
370 }
371 }
372}
373
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200374bool TIntermAggregate::areChildrenConstQualified()
375{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800376 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200377 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800378 TIntermTyped *typedArg = arg->getAsTyped();
379 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200380 {
381 return false;
382 }
383 }
384 return true;
385}
386
Olli Etuahod2a67b92014-10-21 16:42:57 +0300387void TIntermAggregate::setPrecisionFromChildren()
388{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300389 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300390 if (getBasicType() == EbtBool)
391 {
392 mType.setPrecision(EbpUndefined);
393 return;
394 }
395
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500396 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800397 TIntermSequence::iterator childIter = mArguments.begin();
398 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300399 {
400 TIntermTyped *typed = (*childIter)->getAsTyped();
401 if (typed)
402 precision = GetHigherPrecision(typed->getPrecision(), precision);
403 ++childIter;
404 }
405 mType.setPrecision(precision);
406}
407
Olli Etuaho9250cb22017-01-21 10:51:27 +0000408void TIntermAggregate::setPrecisionForBuiltInOp()
409{
410 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800411 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000412 if (!setPrecisionForSpecialBuiltInOp())
413 {
414 setPrecisionFromChildren();
415 }
416}
417
418bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
419{
420 switch (mOp)
421 {
422 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800423 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
424 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000425 return true;
426 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800427 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
428 mArguments[1]->getAsTyped()->getPrecision()));
429 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000430 return true;
431 case EOpUaddCarry:
432 case EOpUsubBorrow:
433 mType.setPrecision(EbpHigh);
434 return true;
435 default:
436 return false;
437 }
438}
439
Olli Etuahod2a67b92014-10-21 16:42:57 +0300440void TIntermAggregate::setBuiltInFunctionPrecision()
441{
442 // All built-ins returning bool should be handled as ops, not functions.
443 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800444 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300445
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800446 TPrecision precision = EbpUndefined;
447 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300448 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800449 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300450 // ESSL spec section 8: texture functions get their precision from the sampler.
451 if (typed && IsSampler(typed->getBasicType()))
452 {
453 precision = typed->getPrecision();
454 break;
455 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300456 }
457 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
458 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho1bb85282017-12-14 13:39:53 +0200459 if (mFunction->name()->find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300460 mType.setPrecision(EbpHigh);
461 else
462 mType.setPrecision(precision);
463}
464
Olli Etuahof2209f72017-04-01 12:45:55 +0300465TString TIntermAggregate::getSymbolTableMangledName() const
466{
467 ASSERT(!isConstructor());
468 switch (mOp)
469 {
470 case EOpCallInternalRawFunction:
471 case EOpCallBuiltInFunction:
472 case EOpCallFunctionInAST:
Olli Etuaho1bb85282017-12-14 13:39:53 +0200473 return TFunction::GetMangledNameFromCall(*mFunction->name(), mArguments);
Olli Etuahof2209f72017-04-01 12:45:55 +0300474 default:
475 TString opString = GetOperatorString(mOp);
476 return TFunction::GetMangledNameFromCall(opString, mArguments);
477 }
478}
479
Olli Etuaho0c371002017-12-13 17:00:25 +0400480const char *TIntermAggregate::functionName() const
481{
482 ASSERT(!isConstructor());
483 switch (mOp)
484 {
485 case EOpCallInternalRawFunction:
486 case EOpCallBuiltInFunction:
487 case EOpCallFunctionInAST:
488 return mFunction->name()->c_str();
489 default:
490 return GetOperatorString(mOp);
491 }
492}
493
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300494bool TIntermAggregate::hasSideEffects() const
495{
Olli Etuaho0c371002017-12-13 17:00:25 +0400496 if (isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300497 {
498 for (TIntermNode *arg : mArguments)
499 {
500 if (arg->getAsTyped()->hasSideEffects())
501 {
502 return true;
503 }
504 }
505 return false;
506 }
507 // Conservatively assume most aggregate operators have side-effects
508 return true;
509}
510
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100511void TIntermBlock::appendStatement(TIntermNode *statement)
512{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300513 // Declaration nodes with no children can appear if it was an empty declaration or if all the
514 // declarators just added constants to the symbol table instead of generating code. We still
515 // need to add the declaration to the AST in that case because it might be relevant to the
516 // validity of switch/case.
517 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100518 {
519 mStatements.push_back(statement);
520 }
521}
522
Olli Etuaho16c745a2017-01-16 17:02:27 +0000523void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
524{
525 ASSERT(parameter != nullptr);
526 mParameters.push_back(parameter);
527}
528
Olli Etuaho13389b62016-10-16 11:48:18 +0100529void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
530{
531 ASSERT(declarator != nullptr);
532 ASSERT(declarator->getAsSymbolNode() != nullptr ||
533 (declarator->getAsBinaryNode() != nullptr &&
534 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
535 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300536 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100537 mDeclarators.push_back(declarator);
538}
539
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300540bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
541{
542 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
543 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
544 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
545 return false;
546}
547
Olli Etuaho57961272016-09-14 13:57:46 +0300548bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400549{
550 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100551 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
552 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400553 return false;
554}
555
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500556bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200557{
558 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100559 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300560 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200561 return false;
562}
563
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500564bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200565{
566 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
567 return false;
568}
569
Olli Etuahod7a25242015-08-18 13:49:45 +0300570TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
571{
572 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
573 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
574 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
575 mLine = node.mLine;
576}
577
Olli Etuahod4f4c112016-04-15 15:11:24 +0300578bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
579{
580 TIntermAggregate *constructor = getAsAggregate();
581 if (!constructor || !constructor->isConstructor())
582 {
583 return false;
584 }
585 for (TIntermNode *&node : *constructor->getSequence())
586 {
587 if (!node->getAsConstantUnion())
588 return false;
589 }
590 return true;
591}
592
Olli Etuahod7a25242015-08-18 13:49:45 +0300593TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
594{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200595 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300596}
597
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200598TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
599 : TIntermTyped(function->getReturnType()), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100600{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200601 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100602}
603
Olli Etuahod7a25242015-08-18 13:49:45 +0300604TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
605 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300606 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100607 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400608 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300609{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800610 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300611 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800612 TIntermTyped *typedArg = arg->getAsTyped();
613 ASSERT(typedArg != nullptr);
614 TIntermTyped *argCopy = typedArg->deepCopy();
615 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300616 }
617}
618
Olli Etuahofe486322017-03-21 09:30:54 +0000619TIntermAggregate *TIntermAggregate::shallowCopy() const
620{
621 TIntermSequence *copySeq = new TIntermSequence();
622 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400623 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000624 copyNode->setLine(mLine);
625 return copyNode;
626}
627
Olli Etuahob6fa0432016-09-28 16:28:05 +0100628TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
629{
630 TIntermTyped *operandCopy = node.mOperand->deepCopy();
631 ASSERT(operandCopy != nullptr);
632 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000633 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100634}
635
Olli Etuahod7a25242015-08-18 13:49:45 +0300636TIntermBinary::TIntermBinary(const TIntermBinary &node)
637 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
638{
639 TIntermTyped *leftCopy = node.mLeft->deepCopy();
640 TIntermTyped *rightCopy = node.mRight->deepCopy();
641 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
642 mLeft = leftCopy;
643 mRight = rightCopy;
644}
645
646TIntermUnary::TIntermUnary(const TIntermUnary &node)
647 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
648{
649 TIntermTyped *operandCopy = node.mOperand->deepCopy();
650 ASSERT(operandCopy != nullptr);
651 mOperand = operandCopy;
652}
653
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300654TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300655{
Olli Etuahod7a25242015-08-18 13:49:45 +0300656 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300657 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
658 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300659 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300660 mCondition = conditionCopy;
661 mTrueExpression = trueCopy;
662 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300663}
664
Jamie Madillb1a85f42014-08-19 15:23:24 -0400665bool TIntermOperator::isAssignment() const
666{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300667 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400668}
669
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300670bool TIntermOperator::isMultiplication() const
671{
672 switch (mOp)
673 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500674 case EOpMul:
675 case EOpMatrixTimesMatrix:
676 case EOpMatrixTimesVector:
677 case EOpMatrixTimesScalar:
678 case EOpVectorTimesMatrix:
679 case EOpVectorTimesScalar:
680 return true;
681 default:
682 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300683 }
684}
685
Jamie Madillb1a85f42014-08-19 15:23:24 -0400686bool TIntermOperator::isConstructor() const
687{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300688 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400689}
690
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800691bool TIntermOperator::isFunctionCall() const
692{
693 switch (mOp)
694 {
695 case EOpCallFunctionInAST:
696 case EOpCallBuiltInFunction:
697 case EOpCallInternalRawFunction:
698 return true;
699 default:
700 return false;
701 }
702}
703
Olli Etuaho1dded802016-08-18 18:13:13 +0300704TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
705{
706 if (left.isMatrix())
707 {
708 if (right.isMatrix())
709 {
710 return EOpMatrixTimesMatrix;
711 }
712 else
713 {
714 if (right.isVector())
715 {
716 return EOpMatrixTimesVector;
717 }
718 else
719 {
720 return EOpMatrixTimesScalar;
721 }
722 }
723 }
724 else
725 {
726 if (right.isMatrix())
727 {
728 if (left.isVector())
729 {
730 return EOpVectorTimesMatrix;
731 }
732 else
733 {
734 return EOpMatrixTimesScalar;
735 }
736 }
737 else
738 {
739 // Neither operand is a matrix.
740 if (left.isVector() == right.isVector())
741 {
742 // Leave as component product.
743 return EOpMul;
744 }
745 else
746 {
747 return EOpVectorTimesScalar;
748 }
749 }
750 }
751}
752
753TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
754{
755 if (left.isMatrix())
756 {
757 if (right.isMatrix())
758 {
759 return EOpMatrixTimesMatrixAssign;
760 }
761 else
762 {
763 // right should be scalar, but this may not be validated yet.
764 return EOpMatrixTimesScalarAssign;
765 }
766 }
767 else
768 {
769 if (right.isMatrix())
770 {
771 // Left should be a vector, but this may not be validated yet.
772 return EOpVectorTimesMatrixAssign;
773 }
774 else
775 {
776 // Neither operand is a matrix.
777 if (left.isVector() == right.isVector())
778 {
779 // Leave as component product.
780 return EOpMulAssign;
781 }
782 else
783 {
784 // left should be vector and right should be scalar, but this may not be validated
785 // yet.
786 return EOpVectorTimesScalarAssign;
787 }
788 }
789 }
790}
791
Jamie Madillb1a85f42014-08-19 15:23:24 -0400792//
793// Make sure the type of a unary operator is appropriate for its
794// combination of operation and operand type.
795//
Olli Etuahoa2234302016-08-31 12:05:39 +0300796void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400797{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300798 if (mOp == EOpArrayLength)
799 {
800 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
801 setType(TType(EbtInt, EbpUndefined, EvqConst));
802 return;
803 }
804
Olli Etuahoa2234302016-08-31 12:05:39 +0300805 TQualifier resultQualifier = EvqTemporary;
806 if (mOperand->getQualifier() == EvqConst)
807 resultQualifier = EvqConst;
808
809 unsigned char operandPrimarySize =
810 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400811 switch (mOp)
812 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300813 case EOpFloatBitsToInt:
814 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
815 break;
816 case EOpFloatBitsToUint:
817 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
818 break;
819 case EOpIntBitsToFloat:
820 case EOpUintBitsToFloat:
821 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
822 break;
823 case EOpPackSnorm2x16:
824 case EOpPackUnorm2x16:
825 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800826 case EOpPackUnorm4x8:
827 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300828 setType(TType(EbtUInt, EbpHigh, resultQualifier));
829 break;
830 case EOpUnpackSnorm2x16:
831 case EOpUnpackUnorm2x16:
832 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
833 break;
834 case EOpUnpackHalf2x16:
835 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
836 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800837 case EOpUnpackUnorm4x8:
838 case EOpUnpackSnorm4x8:
839 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
840 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300841 case EOpAny:
842 case EOpAll:
843 setType(TType(EbtBool, EbpUndefined, resultQualifier));
844 break;
845 case EOpLength:
846 case EOpDeterminant:
847 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
848 break;
849 case EOpTranspose:
850 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
851 static_cast<unsigned char>(mOperand->getType().getRows()),
852 static_cast<unsigned char>(mOperand->getType().getCols())));
853 break;
854 case EOpIsInf:
855 case EOpIsNan:
856 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
857 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000858 case EOpBitfieldReverse:
859 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
860 break;
861 case EOpBitCount:
862 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
863 break;
864 case EOpFindLSB:
865 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
866 break;
867 case EOpFindMSB:
868 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
869 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300870 default:
871 setType(mOperand->getType());
872 mType.setQualifier(resultQualifier);
873 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400874 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300875}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400876
Olli Etuahob6fa0432016-09-28 16:28:05 +0100877TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
878 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
879 mOperand(operand),
880 mSwizzleOffsets(swizzleOffsets)
881{
882 ASSERT(mSwizzleOffsets.size() <= 4);
883 promote();
884}
885
Olli Etuahoa2234302016-08-31 12:05:39 +0300886TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
887 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
888{
889 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400890}
891
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300892TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
893 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
894{
895 promote();
896}
897
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000898TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
899 : TIntermNode(), mSymbol(symbol)
900{
901 ASSERT(symbol);
902 setLine(line);
903}
904
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300905TIntermTernary::TIntermTernary(TIntermTyped *cond,
906 TIntermTyped *trueExpression,
907 TIntermTyped *falseExpression)
908 : TIntermTyped(trueExpression->getType()),
909 mCondition(cond),
910 mTrueExpression(trueExpression),
911 mFalseExpression(falseExpression)
912{
913 getTypePointer()->setQualifier(
914 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
915}
916
Olli Etuaho81629262017-04-19 11:56:01 +0300917TIntermLoop::TIntermLoop(TLoopType type,
918 TIntermNode *init,
919 TIntermTyped *cond,
920 TIntermTyped *expr,
921 TIntermBlock *body)
922 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
923{
924 // Declaration nodes with no children can appear if all the declarators just added constants to
925 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
926 if (mInit && mInit->getAsDeclarationNode() &&
927 mInit->getAsDeclarationNode()->getSequence()->empty())
928 {
929 mInit = nullptr;
930 }
931}
932
Olli Etuaho923ecef2017-10-11 12:01:38 +0300933TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
934 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
935{
936 // Prune empty false blocks so that there won't be unnecessary operations done on it.
937 if (mFalseBlock && mFalseBlock->getSequence()->empty())
938 {
939 mFalseBlock = nullptr;
940 }
941}
942
943TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
944 : TIntermNode(), mInit(init), mStatementList(statementList)
945{
946 ASSERT(mStatementList);
947}
948
949void TIntermSwitch::setStatementList(TIntermBlock *statementList)
950{
951 ASSERT(statementList);
952 mStatementList = statementList;
953}
954
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300955// static
956TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
957 TIntermTyped *trueExpression,
958 TIntermTyped *falseExpression)
959{
960 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
961 falseExpression->getQualifier() == EvqConst)
962 {
963 return EvqConst;
964 }
965 return EvqTemporary;
966}
967
Olli Etuahoeb7f90f2017-07-07 17:25:23 +0300968TIntermTyped *TIntermTernary::fold()
969{
970 if (mCondition->getAsConstantUnion())
971 {
972 if (mCondition->getAsConstantUnion()->getBConst(0))
973 {
974 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
975 return mTrueExpression;
976 }
977 else
978 {
979 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
980 return mFalseExpression;
981 }
982 }
983 return this;
984}
985
Olli Etuahob6fa0432016-09-28 16:28:05 +0100986void TIntermSwizzle::promote()
987{
988 TQualifier resultQualifier = EvqTemporary;
989 if (mOperand->getQualifier() == EvqConst)
990 resultQualifier = EvqConst;
991
992 auto numFields = mSwizzleOffsets.size();
993 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
994 static_cast<unsigned char>(numFields)));
995}
996
997bool TIntermSwizzle::hasDuplicateOffsets() const
998{
999 int offsetCount[4] = {0u, 0u, 0u, 0u};
1000 for (const auto offset : mSwizzleOffsets)
1001 {
1002 offsetCount[offset]++;
1003 if (offsetCount[offset] > 1)
1004 {
1005 return true;
1006 }
1007 }
1008 return false;
1009}
1010
Olli Etuaho09b04a22016-12-15 13:30:26 +00001011bool TIntermSwizzle::offsetsMatch(int offset) const
1012{
1013 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1014}
1015
Olli Etuahob6fa0432016-09-28 16:28:05 +01001016void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1017{
1018 for (const int offset : mSwizzleOffsets)
1019 {
1020 switch (offset)
1021 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001022 case 0:
1023 *out << "x";
1024 break;
1025 case 1:
1026 *out << "y";
1027 break;
1028 case 2:
1029 *out << "z";
1030 break;
1031 case 3:
1032 *out << "w";
1033 break;
1034 default:
1035 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001036 }
1037 }
1038}
1039
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001040TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1041 const TIntermTyped *left,
1042 const TIntermTyped *right)
1043{
1044 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1045 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1046 right->getQualifier() != EvqConst)
1047 {
1048 return EvqTemporary;
1049 }
1050 return EvqConst;
1051}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001052
1053// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001054void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001055{
Olli Etuaho1dded802016-08-18 18:13:13 +03001056 ASSERT(!isMultiplication() ||
1057 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1058
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001059 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1060 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001061 if (mOp == EOpComma)
1062 {
1063 setType(mRight->getType());
1064 return;
1065 }
1066
Jamie Madillb1a85f42014-08-19 15:23:24 -04001067 // Base assumption: just make the type the same as the left
1068 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001069 setType(mLeft->getType());
1070
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001071 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001072 // Binary operations results in temporary variables unless both
1073 // operands are const.
1074 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1075 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001076 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001077 getTypePointer()->setQualifier(EvqTemporary);
1078 }
1079
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001080 // Handle indexing ops.
1081 switch (mOp)
1082 {
1083 case EOpIndexDirect:
1084 case EOpIndexIndirect:
1085 if (mLeft->isArray())
1086 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001087 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001088 }
1089 else if (mLeft->isMatrix())
1090 {
1091 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1092 static_cast<unsigned char>(mLeft->getRows())));
1093 }
1094 else if (mLeft->isVector())
1095 {
1096 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1097 }
1098 else
1099 {
1100 UNREACHABLE();
1101 }
1102 return;
1103 case EOpIndexDirectStruct:
1104 {
1105 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1106 const int i = mRight->getAsConstantUnion()->getIConst(0);
1107 setType(*fields[i]->type());
1108 getTypePointer()->setQualifier(resultQualifier);
1109 return;
1110 }
1111 case EOpIndexDirectInterfaceBlock:
1112 {
1113 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1114 const int i = mRight->getAsConstantUnion()->getIConst(0);
1115 setType(*fields[i]->type());
1116 getTypePointer()->setQualifier(resultQualifier);
1117 return;
1118 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001119 default:
1120 break;
1121 }
1122
1123 ASSERT(mLeft->isArray() == mRight->isArray());
1124
1125 // The result gets promoted to the highest precision.
1126 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1127 getTypePointer()->setPrecision(higherPrecision);
1128
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001129 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001130
1131 //
1132 // All scalars or structs. Code after this test assumes this case is removed!
1133 //
1134 if (nominalSize == 1)
1135 {
1136 switch (mOp)
1137 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001138 //
1139 // Promote to conditional
1140 //
1141 case EOpEqual:
1142 case EOpNotEqual:
1143 case EOpLessThan:
1144 case EOpGreaterThan:
1145 case EOpLessThanEqual:
1146 case EOpGreaterThanEqual:
1147 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1148 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001149
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001150 //
1151 // And and Or operate on conditionals
1152 //
1153 case EOpLogicalAnd:
1154 case EOpLogicalXor:
1155 case EOpLogicalOr:
1156 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1157 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1158 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001159
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001160 default:
1161 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001162 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001163 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001164 }
1165
1166 // If we reach here, at least one of the operands is vector or matrix.
1167 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001168 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001169
Jamie Madillb1a85f42014-08-19 15:23:24 -04001170 switch (mOp)
1171 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001172 case EOpMul:
1173 break;
1174 case EOpMatrixTimesScalar:
1175 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001176 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001177 setType(TType(basicType, higherPrecision, resultQualifier,
1178 static_cast<unsigned char>(mRight->getCols()),
1179 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001180 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001181 break;
1182 case EOpMatrixTimesVector:
1183 setType(TType(basicType, higherPrecision, resultQualifier,
1184 static_cast<unsigned char>(mLeft->getRows()), 1));
1185 break;
1186 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001187 setType(TType(basicType, higherPrecision, resultQualifier,
1188 static_cast<unsigned char>(mRight->getCols()),
1189 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001190 break;
1191 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001192 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001193 static_cast<unsigned char>(nominalSize), 1));
1194 break;
1195 case EOpVectorTimesMatrix:
1196 setType(TType(basicType, higherPrecision, resultQualifier,
1197 static_cast<unsigned char>(mRight->getCols()), 1));
1198 break;
1199 case EOpMulAssign:
1200 case EOpVectorTimesScalarAssign:
1201 case EOpVectorTimesMatrixAssign:
1202 case EOpMatrixTimesScalarAssign:
1203 case EOpMatrixTimesMatrixAssign:
1204 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1205 break;
1206 case EOpAssign:
1207 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001208 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1209 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1210 break;
1211 case EOpAdd:
1212 case EOpSub:
1213 case EOpDiv:
1214 case EOpIMod:
1215 case EOpBitShiftLeft:
1216 case EOpBitShiftRight:
1217 case EOpBitwiseAnd:
1218 case EOpBitwiseXor:
1219 case EOpBitwiseOr:
1220 case EOpAddAssign:
1221 case EOpSubAssign:
1222 case EOpDivAssign:
1223 case EOpIModAssign:
1224 case EOpBitShiftLeftAssign:
1225 case EOpBitShiftRightAssign:
1226 case EOpBitwiseAndAssign:
1227 case EOpBitwiseXorAssign:
1228 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001229 {
1230 const int secondarySize =
1231 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1232 setType(TType(basicType, higherPrecision, resultQualifier,
1233 static_cast<unsigned char>(nominalSize),
1234 static_cast<unsigned char>(secondarySize)));
1235 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001236 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001237 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001238 case EOpEqual:
1239 case EOpNotEqual:
1240 case EOpLessThan:
1241 case EOpGreaterThan:
1242 case EOpLessThanEqual:
1243 case EOpGreaterThanEqual:
1244 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1245 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001246 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001247 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001248
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001249 case EOpIndexDirect:
1250 case EOpIndexIndirect:
1251 case EOpIndexDirectInterfaceBlock:
1252 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001253 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001254 UNREACHABLE();
1255 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001256 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001257 UNREACHABLE();
1258 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001259 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001260}
1261
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001262const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001263{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001264 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001265 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001266 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001267 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001268 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001269 size_t arrayElementSize = arrayElementType.getObjectSize();
1270 return &mUnionArrayPointer[arrayElementSize * index];
1271 }
1272 else if (isMatrix())
1273 {
1274 ASSERT(index < getType().getCols());
1275 int size = getType().getRows();
1276 return &mUnionArrayPointer[size * index];
1277 }
1278 else if (isVector())
1279 {
1280 ASSERT(index < getType().getNominalSize());
1281 return &mUnionArrayPointer[index];
1282 }
1283 else
1284 {
1285 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001286 return nullptr;
1287 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001288}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001289
Olli Etuahob6fa0432016-09-28 16:28:05 +01001290TIntermTyped *TIntermSwizzle::fold()
1291{
1292 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1293 if (operandConstant == nullptr)
1294 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001295 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001296 }
1297
1298 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1299 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1300 {
1301 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1302 }
1303 return CreateFoldedNode(constArray, this, mType.getQualifier());
1304}
1305
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001306TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1307{
1308 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1309 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1310 switch (mOp)
1311 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001312 case EOpComma:
1313 {
1314 if (mLeft->hasSideEffects())
1315 {
1316 return this;
1317 }
1318 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1319 return mRight;
1320 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001321 case EOpIndexDirect:
1322 {
1323 if (leftConstant == nullptr || rightConstant == nullptr)
1324 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001325 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001326 }
1327 int index = rightConstant->getIConst(0);
1328
1329 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001330 if (!constArray)
1331 {
1332 return this;
1333 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001334 return CreateFoldedNode(constArray, this, mType.getQualifier());
1335 }
1336 case EOpIndexDirectStruct:
1337 {
1338 if (leftConstant == nullptr || rightConstant == nullptr)
1339 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001340 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001341 }
1342 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1343 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1344
1345 size_t previousFieldsSize = 0;
1346 for (size_t i = 0; i < index; ++i)
1347 {
1348 previousFieldsSize += fields[i]->type()->getObjectSize();
1349 }
1350
1351 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1352 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1353 }
1354 case EOpIndexIndirect:
1355 case EOpIndexDirectInterfaceBlock:
1356 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001357 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001358 default:
1359 {
1360 if (leftConstant == nullptr || rightConstant == nullptr)
1361 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001362 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001363 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001364 TConstantUnion *constArray =
1365 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001366 if (!constArray)
1367 {
1368 return this;
1369 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001370
1371 // Nodes may be constant folded without being qualified as constant.
1372 return CreateFoldedNode(constArray, this, mType.getQualifier());
1373 }
1374 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001375}
1376
Olli Etuahof119a262016-08-19 15:54:22 +03001377TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001378{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301379 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001380
1381 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301382 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001383 // The size of runtime-sized arrays may only be determined at runtime.
1384 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001385 {
1386 return this;
1387 }
1388 constArray = new TConstantUnion[1];
1389 constArray->setIConst(mOperand->getOutermostArraySize());
1390 }
1391 else
1392 {
1393 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1394 if (operandConstant == nullptr)
1395 {
1396 return this;
1397 }
1398
1399 switch (mOp)
1400 {
1401 case EOpAny:
1402 case EOpAll:
1403 case EOpLength:
1404 case EOpTranspose:
1405 case EOpDeterminant:
1406 case EOpInverse:
1407 case EOpPackSnorm2x16:
1408 case EOpUnpackSnorm2x16:
1409 case EOpPackUnorm2x16:
1410 case EOpUnpackUnorm2x16:
1411 case EOpPackHalf2x16:
1412 case EOpUnpackHalf2x16:
1413 case EOpPackUnorm4x8:
1414 case EOpPackSnorm4x8:
1415 case EOpUnpackUnorm4x8:
1416 case EOpUnpackSnorm4x8:
1417 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1418 break;
1419 default:
1420 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1421 break;
1422 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301423 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001424 if (constArray == nullptr)
1425 {
1426 return this;
1427 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001428
1429 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001430 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001431}
1432
Olli Etuahof119a262016-08-19 15:54:22 +03001433TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001434{
1435 // Make sure that all params are constant before actual constant folding.
1436 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001437 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001438 if (param->getAsConstantUnion() == nullptr)
1439 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001440 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001441 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001442 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001443 TConstantUnion *constArray = nullptr;
1444 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001445 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001446 else
Olli Etuahof119a262016-08-19 15:54:22 +03001447 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001448
1449 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001450 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001451}
1452
Jamie Madillb1a85f42014-08-19 15:23:24 -04001453//
1454// The fold functions see if an operation on a constant can be done in place,
1455// without generating run-time code.
1456//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001457// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001458//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001459TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1460 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001461 TDiagnostics *diagnostics,
1462 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001463{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001464 const TConstantUnion *leftArray = getUnionArrayPointer();
1465 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001466
Olli Etuahof119a262016-08-19 15:54:22 +03001467 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001468
1469 size_t objectSize = getType().getObjectSize();
1470
1471 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1472 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1473 {
1474 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1475 }
1476 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1477 {
1478 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001479 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001480 objectSize = rightNode->getType().getObjectSize();
1481 }
1482
1483 TConstantUnion *resultArray = nullptr;
1484
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001485 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001486 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001487 case EOpAdd:
1488 resultArray = new TConstantUnion[objectSize];
1489 for (size_t i = 0; i < objectSize; i++)
1490 resultArray[i] =
1491 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1492 break;
1493 case EOpSub:
1494 resultArray = new TConstantUnion[objectSize];
1495 for (size_t i = 0; i < objectSize; i++)
1496 resultArray[i] =
1497 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1498 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001499
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001500 case EOpMul:
1501 case EOpVectorTimesScalar:
1502 case EOpMatrixTimesScalar:
1503 resultArray = new TConstantUnion[objectSize];
1504 for (size_t i = 0; i < objectSize; i++)
1505 resultArray[i] =
1506 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1507 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001508
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001509 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001510 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001511 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001512 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001513
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001514 const int leftCols = getCols();
1515 const int leftRows = getRows();
1516 const int rightCols = rightNode->getType().getCols();
1517 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001518 const int resultCols = rightCols;
1519 const int resultRows = leftRows;
1520
1521 resultArray = new TConstantUnion[resultCols * resultRows];
1522 for (int row = 0; row < resultRows; row++)
1523 {
1524 for (int column = 0; column < resultCols; column++)
1525 {
1526 resultArray[resultRows * column + row].setFConst(0.0f);
1527 for (int i = 0; i < leftCols; i++)
1528 {
1529 resultArray[resultRows * column + row].setFConst(
1530 resultArray[resultRows * column + row].getFConst() +
1531 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001532 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001533 }
1534 }
1535 }
1536 }
1537 break;
1538
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001539 case EOpDiv:
1540 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001541 {
1542 resultArray = new TConstantUnion[objectSize];
1543 for (size_t i = 0; i < objectSize; i++)
1544 {
1545 switch (getType().getBasicType())
1546 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001547 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001548 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001549 ASSERT(op == EOpDiv);
1550 float dividend = leftArray[i].getFConst();
1551 float divisor = rightArray[i].getFConst();
1552 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001553 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001554 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001555 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001556 diagnostics->warning(
1557 getLine(),
1558 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001559 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001560 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001561 }
1562 else
1563 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001564 diagnostics->warning(getLine(),
1565 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001566 bool negativeResult =
1567 std::signbit(dividend) != std::signbit(divisor);
1568 resultArray[i].setFConst(
1569 negativeResult ? -std::numeric_limits<float>::infinity()
1570 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001571 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001572 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001573 else if (gl::isInf(dividend) && gl::isInf(divisor))
1574 {
1575 diagnostics->warning(getLine(),
1576 "Infinity divided by infinity during constant "
1577 "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());
1580 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001581 else
1582 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001583 float result = dividend / divisor;
1584 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001585 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001586 diagnostics->warning(
1587 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001588 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001589 }
1590 resultArray[i].setFConst(result);
1591 }
1592 break;
1593 }
1594 case EbtInt:
1595 if (rightArray[i] == 0)
1596 {
1597 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001598 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001599 resultArray[i].setIConst(INT_MAX);
1600 }
1601 else
1602 {
1603 int lhs = leftArray[i].getIConst();
1604 int divisor = rightArray[i].getIConst();
1605 if (op == EOpDiv)
1606 {
1607 // Check for the special case where the minimum representable number
1608 // is
1609 // divided by -1. If left alone this leads to integer overflow in
1610 // C++.
1611 // ESSL 3.00.6 section 4.1.3 Integers:
1612 // "However, for the case where the minimum representable value is
1613 // divided by -1, it is allowed to return either the minimum
1614 // representable value or the maximum representable value."
1615 if (lhs == -0x7fffffff - 1 && divisor == -1)
1616 {
1617 resultArray[i].setIConst(0x7fffffff);
1618 }
1619 else
1620 {
1621 resultArray[i].setIConst(lhs / divisor);
1622 }
Olli Etuahod4453572016-09-27 13:21:46 +01001623 }
1624 else
1625 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001626 ASSERT(op == EOpIMod);
1627 if (lhs < 0 || divisor < 0)
1628 {
1629 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1630 // when
1631 // either one of the operands is negative.
1632 diagnostics->warning(getLine(),
1633 "Negative modulus operator operand "
1634 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001635 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001636 resultArray[i].setIConst(0);
1637 }
1638 else
1639 {
1640 resultArray[i].setIConst(lhs % divisor);
1641 }
Olli Etuahod4453572016-09-27 13:21:46 +01001642 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001643 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001644 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001645
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001646 case EbtUInt:
1647 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001648 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001649 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001650 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001651 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001652 }
1653 else
1654 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001655 if (op == EOpDiv)
1656 {
1657 resultArray[i].setUConst(leftArray[i].getUConst() /
1658 rightArray[i].getUConst());
1659 }
1660 else
1661 {
1662 ASSERT(op == EOpIMod);
1663 resultArray[i].setUConst(leftArray[i].getUConst() %
1664 rightArray[i].getUConst());
1665 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001666 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001667 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001668
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001669 default:
1670 UNREACHABLE();
1671 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001672 }
1673 }
1674 }
1675 break;
1676
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001677 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001678 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001679 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001680 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001681
1682 const int matrixCols = getCols();
1683 const int matrixRows = getRows();
1684
1685 resultArray = new TConstantUnion[matrixRows];
1686
1687 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1688 {
1689 resultArray[matrixRow].setFConst(0.0f);
1690 for (int col = 0; col < matrixCols; col++)
1691 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001692 resultArray[matrixRow].setFConst(
1693 resultArray[matrixRow].getFConst() +
1694 leftArray[col * matrixRows + matrixRow].getFConst() *
1695 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001696 }
1697 }
1698 }
1699 break;
1700
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001701 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001702 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001703 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001704 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001705
1706 const int matrixCols = rightNode->getType().getCols();
1707 const int matrixRows = rightNode->getType().getRows();
1708
1709 resultArray = new TConstantUnion[matrixCols];
1710
1711 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1712 {
1713 resultArray[matrixCol].setFConst(0.0f);
1714 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1715 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001716 resultArray[matrixCol].setFConst(
1717 resultArray[matrixCol].getFConst() +
1718 leftArray[matrixRow].getFConst() *
1719 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001720 }
1721 }
1722 }
1723 break;
1724
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001725 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001726 {
1727 resultArray = new TConstantUnion[objectSize];
1728 for (size_t i = 0; i < objectSize; i++)
1729 {
1730 resultArray[i] = leftArray[i] && rightArray[i];
1731 }
1732 }
1733 break;
1734
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001735 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001736 {
1737 resultArray = new TConstantUnion[objectSize];
1738 for (size_t i = 0; i < objectSize; i++)
1739 {
1740 resultArray[i] = leftArray[i] || rightArray[i];
1741 }
1742 }
1743 break;
1744
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001745 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001746 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001747 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001748 resultArray = new TConstantUnion[objectSize];
1749 for (size_t i = 0; i < objectSize; i++)
1750 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001751 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001752 }
1753 }
1754 break;
1755
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001756 case EOpBitwiseAnd:
1757 resultArray = new TConstantUnion[objectSize];
1758 for (size_t i = 0; i < objectSize; i++)
1759 resultArray[i] = leftArray[i] & rightArray[i];
1760 break;
1761 case EOpBitwiseXor:
1762 resultArray = new TConstantUnion[objectSize];
1763 for (size_t i = 0; i < objectSize; i++)
1764 resultArray[i] = leftArray[i] ^ rightArray[i];
1765 break;
1766 case EOpBitwiseOr:
1767 resultArray = new TConstantUnion[objectSize];
1768 for (size_t i = 0; i < objectSize; i++)
1769 resultArray[i] = leftArray[i] | rightArray[i];
1770 break;
1771 case EOpBitShiftLeft:
1772 resultArray = new TConstantUnion[objectSize];
1773 for (size_t i = 0; i < objectSize; i++)
1774 resultArray[i] =
1775 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1776 break;
1777 case EOpBitShiftRight:
1778 resultArray = new TConstantUnion[objectSize];
1779 for (size_t i = 0; i < objectSize; i++)
1780 resultArray[i] =
1781 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1782 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001783
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001784 case EOpLessThan:
1785 ASSERT(objectSize == 1);
1786 resultArray = new TConstantUnion[1];
1787 resultArray->setBConst(*leftArray < *rightArray);
1788 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001789
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001790 case EOpGreaterThan:
1791 ASSERT(objectSize == 1);
1792 resultArray = new TConstantUnion[1];
1793 resultArray->setBConst(*leftArray > *rightArray);
1794 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001795
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001796 case EOpLessThanEqual:
1797 ASSERT(objectSize == 1);
1798 resultArray = new TConstantUnion[1];
1799 resultArray->setBConst(!(*leftArray > *rightArray));
1800 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001801
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001802 case EOpGreaterThanEqual:
1803 ASSERT(objectSize == 1);
1804 resultArray = new TConstantUnion[1];
1805 resultArray->setBConst(!(*leftArray < *rightArray));
1806 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001807
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001808 case EOpEqual:
1809 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001810 {
1811 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001812 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001813 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001814 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001815 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001816 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001817 equal = false;
1818 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001819 }
1820 }
1821 if (op == EOpEqual)
1822 {
1823 resultArray->setBConst(equal);
1824 }
1825 else
1826 {
1827 resultArray->setBConst(!equal);
1828 }
1829 }
1830 break;
1831
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001832 default:
1833 UNREACHABLE();
1834 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001835 }
1836 return resultArray;
1837}
1838
Olli Etuahof119a262016-08-19 15:54:22 +03001839// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1840// code. Returns the constant value to keep using. Nullptr should not be returned.
1841TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001842{
Olli Etuahof119a262016-08-19 15:54:22 +03001843 // Do operations where the return type may have a different number of components compared to the
1844 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001845
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001846 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001847 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301848
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001849 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301850 TConstantUnion *resultArray = nullptr;
1851 switch (op)
1852 {
Olli Etuahof119a262016-08-19 15:54:22 +03001853 case EOpAny:
1854 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301855 resultArray = new TConstantUnion();
1856 resultArray->setBConst(false);
1857 for (size_t i = 0; i < objectSize; i++)
1858 {
1859 if (operandArray[i].getBConst())
1860 {
1861 resultArray->setBConst(true);
1862 break;
1863 }
1864 }
1865 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301866
Olli Etuahof119a262016-08-19 15:54:22 +03001867 case EOpAll:
1868 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301869 resultArray = new TConstantUnion();
1870 resultArray->setBConst(true);
1871 for (size_t i = 0; i < objectSize; i++)
1872 {
1873 if (!operandArray[i].getBConst())
1874 {
1875 resultArray->setBConst(false);
1876 break;
1877 }
1878 }
1879 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301880
Olli Etuahof119a262016-08-19 15:54:22 +03001881 case EOpLength:
1882 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301883 resultArray = new TConstantUnion();
1884 resultArray->setFConst(VectorLength(operandArray, objectSize));
1885 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301886
Olli Etuahof119a262016-08-19 15:54:22 +03001887 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301888 {
Olli Etuahof119a262016-08-19 15:54:22 +03001889 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301890 resultArray = new TConstantUnion[objectSize];
1891 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001892 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301893 SetUnionArrayFromMatrix(result, resultArray);
1894 break;
1895 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301896
Olli Etuahof119a262016-08-19 15:54:22 +03001897 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301898 {
Olli Etuahof119a262016-08-19 15:54:22 +03001899 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301900 unsigned int size = getType().getNominalSize();
1901 ASSERT(size >= 2 && size <= 4);
1902 resultArray = new TConstantUnion();
1903 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1904 break;
1905 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301906
Olli Etuahof119a262016-08-19 15:54:22 +03001907 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301908 {
Olli Etuahof119a262016-08-19 15:54:22 +03001909 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301910 unsigned int size = getType().getNominalSize();
1911 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001912 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301913 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1914 SetUnionArrayFromMatrix(result, resultArray);
1915 break;
1916 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301917
Olli Etuahof119a262016-08-19 15:54:22 +03001918 case EOpPackSnorm2x16:
1919 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301920 ASSERT(getType().getNominalSize() == 2);
1921 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001922 resultArray->setUConst(
1923 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301924 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301925
Olli Etuahof119a262016-08-19 15:54:22 +03001926 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301927 {
Olli Etuahof119a262016-08-19 15:54:22 +03001928 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301929 resultArray = new TConstantUnion[2];
1930 float f1, f2;
1931 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1932 resultArray[0].setFConst(f1);
1933 resultArray[1].setFConst(f2);
1934 break;
1935 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301936
Olli Etuahof119a262016-08-19 15:54:22 +03001937 case EOpPackUnorm2x16:
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::packUnorm2x16(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 EOpUnpackUnorm2x16:
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::unpackUnorm2x16(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 EOpPackHalf2x16:
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::packHalf2x16(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 EOpUnpackHalf2x16:
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::unpackHalf2x16(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 Etuaho25aef452017-01-29 16:15:44 -08001975 case EOpPackUnorm4x8:
1976 {
1977 ASSERT(getType().getBasicType() == EbtFloat);
1978 resultArray = new TConstantUnion();
1979 resultArray->setUConst(
1980 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1981 operandArray[2].getFConst(), operandArray[3].getFConst()));
1982 break;
1983 }
1984 case EOpPackSnorm4x8:
1985 {
1986 ASSERT(getType().getBasicType() == EbtFloat);
1987 resultArray = new TConstantUnion();
1988 resultArray->setUConst(
1989 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1990 operandArray[2].getFConst(), operandArray[3].getFConst()));
1991 break;
1992 }
1993 case EOpUnpackUnorm4x8:
1994 {
1995 ASSERT(getType().getBasicType() == EbtUInt);
1996 resultArray = new TConstantUnion[4];
1997 float f[4];
1998 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
1999 for (size_t i = 0; i < 4; ++i)
2000 {
2001 resultArray[i].setFConst(f[i]);
2002 }
2003 break;
2004 }
2005 case EOpUnpackSnorm4x8:
2006 {
2007 ASSERT(getType().getBasicType() == EbtUInt);
2008 resultArray = new TConstantUnion[4];
2009 float f[4];
2010 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2011 for (size_t i = 0; i < 4; ++i)
2012 {
2013 resultArray[i].setFConst(f[i]);
2014 }
2015 break;
2016 }
2017
Olli Etuahof119a262016-08-19 15:54:22 +03002018 default:
2019 UNREACHABLE();
2020 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302021 }
2022
2023 return resultArray;
2024}
2025
Olli Etuahof119a262016-08-19 15:54:22 +03002026TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2027 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302028{
Olli Etuahof119a262016-08-19 15:54:22 +03002029 // Do unary operations where each component of the result is computed based on the corresponding
2030 // component of the operand. Also folds normalize, though the divisor in that case takes all
2031 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302032
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002033 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002034 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002035
2036 size_t objectSize = getType().getObjectSize();
2037
Arun Patoleab2b9a22015-07-06 18:27:56 +05302038 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2039 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302040 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002041 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302042 {
Olli Etuahof119a262016-08-19 15:54:22 +03002043 case EOpNegative:
2044 switch (getType().getBasicType())
2045 {
2046 case EbtFloat:
2047 resultArray[i].setFConst(-operandArray[i].getFConst());
2048 break;
2049 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002050 if (operandArray[i] == std::numeric_limits<int>::min())
2051 {
2052 // The minimum representable integer doesn't have a positive
2053 // counterpart, rather the negation overflows and in ESSL is supposed to
2054 // wrap back to the minimum representable integer. Make sure that we
2055 // don't actually let the negation overflow, which has undefined
2056 // behavior in C++.
2057 resultArray[i].setIConst(std::numeric_limits<int>::min());
2058 }
2059 else
2060 {
2061 resultArray[i].setIConst(-operandArray[i].getIConst());
2062 }
Olli Etuahof119a262016-08-19 15:54:22 +03002063 break;
2064 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002065 if (operandArray[i] == 0x80000000u)
2066 {
2067 resultArray[i].setUConst(0x80000000u);
2068 }
2069 else
2070 {
2071 resultArray[i].setUConst(static_cast<unsigned int>(
2072 -static_cast<int>(operandArray[i].getUConst())));
2073 }
Olli Etuahof119a262016-08-19 15:54:22 +03002074 break;
2075 default:
2076 UNREACHABLE();
2077 return nullptr;
2078 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302079 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302080
Olli Etuahof119a262016-08-19 15:54:22 +03002081 case EOpPositive:
2082 switch (getType().getBasicType())
2083 {
2084 case EbtFloat:
2085 resultArray[i].setFConst(operandArray[i].getFConst());
2086 break;
2087 case EbtInt:
2088 resultArray[i].setIConst(operandArray[i].getIConst());
2089 break;
2090 case EbtUInt:
2091 resultArray[i].setUConst(static_cast<unsigned int>(
2092 static_cast<int>(operandArray[i].getUConst())));
2093 break;
2094 default:
2095 UNREACHABLE();
2096 return nullptr;
2097 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302098 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302099
Olli Etuahof119a262016-08-19 15:54:22 +03002100 case EOpLogicalNot:
2101 switch (getType().getBasicType())
2102 {
2103 case EbtBool:
2104 resultArray[i].setBConst(!operandArray[i].getBConst());
2105 break;
2106 default:
2107 UNREACHABLE();
2108 return nullptr;
2109 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302110 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302111
Olli Etuahof119a262016-08-19 15:54:22 +03002112 case EOpBitwiseNot:
2113 switch (getType().getBasicType())
2114 {
2115 case EbtInt:
2116 resultArray[i].setIConst(~operandArray[i].getIConst());
2117 break;
2118 case EbtUInt:
2119 resultArray[i].setUConst(~operandArray[i].getUConst());
2120 break;
2121 default:
2122 UNREACHABLE();
2123 return nullptr;
2124 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302125 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302126
Olli Etuahof119a262016-08-19 15:54:22 +03002127 case EOpRadians:
2128 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302129 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2130 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302131
Olli Etuahof119a262016-08-19 15:54:22 +03002132 case EOpDegrees:
2133 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302134 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2135 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136
Olli Etuahof119a262016-08-19 15:54:22 +03002137 case EOpSin:
2138 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302139 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302140
Olli Etuahof119a262016-08-19 15:54:22 +03002141 case EOpCos:
2142 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2143 break;
2144
2145 case EOpTan:
2146 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2147 break;
2148
2149 case EOpAsin:
2150 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2151 // 0.
2152 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2153 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2154 diagnostics, &resultArray[i]);
2155 else
2156 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2157 break;
2158
2159 case EOpAcos:
2160 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2161 // 0.
2162 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2163 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2164 diagnostics, &resultArray[i]);
2165 else
2166 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2167 break;
2168
2169 case EOpAtan:
2170 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2171 break;
2172
2173 case EOpSinh:
2174 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2175 break;
2176
2177 case EOpCosh:
2178 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2179 break;
2180
2181 case EOpTanh:
2182 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2183 break;
2184
2185 case EOpAsinh:
2186 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2187 break;
2188
2189 case EOpAcosh:
2190 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2191 if (operandArray[i].getFConst() < 1.0f)
2192 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2193 diagnostics, &resultArray[i]);
2194 else
2195 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2196 break;
2197
2198 case EOpAtanh:
2199 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2200 // 0.
2201 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2202 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2203 diagnostics, &resultArray[i]);
2204 else
2205 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2206 break;
2207
2208 case EOpAbs:
2209 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302210 {
Olli Etuahof119a262016-08-19 15:54:22 +03002211 case EbtFloat:
2212 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2213 break;
2214 case EbtInt:
2215 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2216 break;
2217 default:
2218 UNREACHABLE();
2219 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302220 }
2221 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002222
2223 case EOpSign:
2224 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302225 {
Olli Etuahof119a262016-08-19 15:54:22 +03002226 case EbtFloat:
2227 {
2228 float fConst = operandArray[i].getFConst();
2229 float fResult = 0.0f;
2230 if (fConst > 0.0f)
2231 fResult = 1.0f;
2232 else if (fConst < 0.0f)
2233 fResult = -1.0f;
2234 resultArray[i].setFConst(fResult);
2235 break;
2236 }
2237 case EbtInt:
2238 {
2239 int iConst = operandArray[i].getIConst();
2240 int iResult = 0;
2241 if (iConst > 0)
2242 iResult = 1;
2243 else if (iConst < 0)
2244 iResult = -1;
2245 resultArray[i].setIConst(iResult);
2246 break;
2247 }
2248 default:
2249 UNREACHABLE();
2250 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302251 }
2252 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302253
Olli Etuahof119a262016-08-19 15:54:22 +03002254 case EOpFloor:
2255 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2256 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302257
Olli Etuahof119a262016-08-19 15:54:22 +03002258 case EOpTrunc:
2259 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2260 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302261
Olli Etuahof119a262016-08-19 15:54:22 +03002262 case EOpRound:
2263 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2264 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302265
Olli Etuahof119a262016-08-19 15:54:22 +03002266 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302267 {
Olli Etuahof119a262016-08-19 15:54:22 +03002268 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302269 float x = operandArray[i].getFConst();
2270 float result;
2271 float fractPart = modff(x, &result);
2272 if (fabsf(fractPart) == 0.5f)
2273 result = 2.0f * roundf(x / 2.0f);
2274 else
2275 result = roundf(x);
2276 resultArray[i].setFConst(result);
2277 break;
2278 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302279
Olli Etuahof119a262016-08-19 15:54:22 +03002280 case EOpCeil:
2281 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2282 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302283
Olli Etuahof119a262016-08-19 15:54:22 +03002284 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302285 {
Olli Etuahof119a262016-08-19 15:54:22 +03002286 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302287 float x = operandArray[i].getFConst();
2288 resultArray[i].setFConst(x - floorf(x));
2289 break;
2290 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302291
Olli Etuahof119a262016-08-19 15:54:22 +03002292 case EOpIsNan:
2293 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302294 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2295 break;
Arun Patole551279e2015-07-07 18:18:23 +05302296
Olli Etuahof119a262016-08-19 15:54:22 +03002297 case EOpIsInf:
2298 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302299 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2300 break;
Arun Patole551279e2015-07-07 18:18:23 +05302301
Olli Etuahof119a262016-08-19 15:54:22 +03002302 case EOpFloatBitsToInt:
2303 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302304 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2305 break;
Arun Patole551279e2015-07-07 18:18:23 +05302306
Olli Etuahof119a262016-08-19 15:54:22 +03002307 case EOpFloatBitsToUint:
2308 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302309 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2310 break;
Arun Patole551279e2015-07-07 18:18:23 +05302311
Olli Etuahof119a262016-08-19 15:54:22 +03002312 case EOpIntBitsToFloat:
2313 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302314 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2315 break;
Arun Patole551279e2015-07-07 18:18:23 +05302316
Olli Etuahof119a262016-08-19 15:54:22 +03002317 case EOpUintBitsToFloat:
2318 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302319 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2320 break;
Arun Patole551279e2015-07-07 18:18:23 +05302321
Olli Etuahof119a262016-08-19 15:54:22 +03002322 case EOpExp:
2323 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2324 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302325
Olli Etuahof119a262016-08-19 15:54:22 +03002326 case EOpLog:
2327 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2328 if (operandArray[i].getFConst() <= 0.0f)
2329 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2330 diagnostics, &resultArray[i]);
2331 else
2332 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2333 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302334
Olli Etuahof119a262016-08-19 15:54:22 +03002335 case EOpExp2:
2336 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2337 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302338
Olli Etuahof119a262016-08-19 15:54:22 +03002339 case EOpLog2:
2340 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2341 // And log2f is not available on some plarforms like old android, so just using
2342 // log(x)/log(2) here.
2343 if (operandArray[i].getFConst() <= 0.0f)
2344 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2345 diagnostics, &resultArray[i]);
2346 else
2347 {
2348 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2349 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2350 }
2351 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302352
Olli Etuahof119a262016-08-19 15:54:22 +03002353 case EOpSqrt:
2354 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2355 if (operandArray[i].getFConst() < 0.0f)
2356 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2357 diagnostics, &resultArray[i]);
2358 else
2359 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2360 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302361
Olli Etuahof119a262016-08-19 15:54:22 +03002362 case EOpInverseSqrt:
2363 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2364 // so getting the square root first using builtin function sqrt() and then taking
2365 // its inverse.
2366 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2367 // result to 0.
2368 if (operandArray[i].getFConst() <= 0.0f)
2369 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2370 diagnostics, &resultArray[i]);
2371 else
2372 {
2373 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2374 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2375 }
2376 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302377
Olli Etuahod68924e2017-01-02 17:34:40 +00002378 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002379 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302380 resultArray[i].setBConst(!operandArray[i].getBConst());
2381 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302382
Olli Etuahof119a262016-08-19 15:54:22 +03002383 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302384 {
Olli Etuahof119a262016-08-19 15:54:22 +03002385 ASSERT(getType().getBasicType() == EbtFloat);
2386 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302387 float length = VectorLength(operandArray, objectSize);
2388 if (length)
2389 resultArray[i].setFConst(x / length);
2390 else
Olli Etuahof119a262016-08-19 15:54:22 +03002391 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2392 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302393 break;
2394 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002395 case EOpBitfieldReverse:
2396 {
2397 uint32_t value;
2398 if (getType().getBasicType() == EbtInt)
2399 {
2400 value = static_cast<uint32_t>(operandArray[i].getIConst());
2401 }
2402 else
2403 {
2404 ASSERT(getType().getBasicType() == EbtUInt);
2405 value = operandArray[i].getUConst();
2406 }
2407 uint32_t result = gl::BitfieldReverse(value);
2408 if (getType().getBasicType() == EbtInt)
2409 {
2410 resultArray[i].setIConst(static_cast<int32_t>(result));
2411 }
2412 else
2413 {
2414 resultArray[i].setUConst(result);
2415 }
2416 break;
2417 }
2418 case EOpBitCount:
2419 {
2420 uint32_t value;
2421 if (getType().getBasicType() == EbtInt)
2422 {
2423 value = static_cast<uint32_t>(operandArray[i].getIConst());
2424 }
2425 else
2426 {
2427 ASSERT(getType().getBasicType() == EbtUInt);
2428 value = operandArray[i].getUConst();
2429 }
2430 int result = gl::BitCount(value);
2431 resultArray[i].setIConst(result);
2432 break;
2433 }
2434 case EOpFindLSB:
2435 {
2436 uint32_t value;
2437 if (getType().getBasicType() == EbtInt)
2438 {
2439 value = static_cast<uint32_t>(operandArray[i].getIConst());
2440 }
2441 else
2442 {
2443 ASSERT(getType().getBasicType() == EbtUInt);
2444 value = operandArray[i].getUConst();
2445 }
2446 resultArray[i].setIConst(gl::FindLSB(value));
2447 break;
2448 }
2449 case EOpFindMSB:
2450 {
2451 uint32_t value;
2452 if (getType().getBasicType() == EbtInt)
2453 {
2454 int intValue = operandArray[i].getIConst();
2455 value = static_cast<uint32_t>(intValue);
2456 if (intValue < 0)
2457 {
2458 // Look for zero instead of one in value. This also handles the intValue ==
2459 // -1 special case, where the return value needs to be -1.
2460 value = ~value;
2461 }
2462 }
2463 else
2464 {
2465 ASSERT(getType().getBasicType() == EbtUInt);
2466 value = operandArray[i].getUConst();
2467 }
2468 resultArray[i].setIConst(gl::FindMSB(value));
2469 break;
2470 }
Olli Etuahof119a262016-08-19 15:54:22 +03002471 case EOpDFdx:
2472 case EOpDFdy:
2473 case EOpFwidth:
2474 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302475 // Derivatives of constant arguments should be 0.
2476 resultArray[i].setFConst(0.0f);
2477 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302478
Olli Etuahof119a262016-08-19 15:54:22 +03002479 default:
2480 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302481 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302482 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002483
Arun Patoleab2b9a22015-07-06 18:27:56 +05302484 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002485}
2486
Olli Etuahof119a262016-08-19 15:54:22 +03002487void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2488 FloatTypeUnaryFunc builtinFunc,
2489 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302490{
2491 ASSERT(builtinFunc);
2492
Olli Etuahof119a262016-08-19 15:54:22 +03002493 ASSERT(getType().getBasicType() == EbtFloat);
2494 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302495}
2496
Jamie Madillb1a85f42014-08-19 15:23:24 -04002497// static
Olli Etuahof119a262016-08-19 15:54:22 +03002498TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002499{
2500 ASSERT(aggregate->getSequence()->size() > 0u);
2501 size_t resultSize = aggregate->getType().getObjectSize();
2502 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2503 TBasicType basicType = aggregate->getBasicType();
2504
2505 size_t resultIndex = 0u;
2506
2507 if (aggregate->getSequence()->size() == 1u)
2508 {
2509 TIntermNode *argument = aggregate->getSequence()->front();
2510 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2511 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2512 // Check the special case of constructing a matrix diagonal from a single scalar,
2513 // or a vector from a single scalar.
2514 if (argumentConstant->getType().getObjectSize() == 1u)
2515 {
2516 if (aggregate->isMatrix())
2517 {
2518 int resultCols = aggregate->getType().getCols();
2519 int resultRows = aggregate->getType().getRows();
2520 for (int col = 0; col < resultCols; ++col)
2521 {
2522 for (int row = 0; row < resultRows; ++row)
2523 {
2524 if (col == row)
2525 {
2526 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2527 }
2528 else
2529 {
2530 resultArray[resultIndex].setFConst(0.0f);
2531 }
2532 ++resultIndex;
2533 }
2534 }
2535 }
2536 else
2537 {
2538 while (resultIndex < resultSize)
2539 {
2540 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2541 ++resultIndex;
2542 }
2543 }
2544 ASSERT(resultIndex == resultSize);
2545 return resultArray;
2546 }
2547 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2548 {
2549 // The special case of constructing a matrix from a matrix.
2550 int argumentCols = argumentConstant->getType().getCols();
2551 int argumentRows = argumentConstant->getType().getRows();
2552 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002553 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002554 for (int col = 0; col < resultCols; ++col)
2555 {
2556 for (int row = 0; row < resultRows; ++row)
2557 {
2558 if (col < argumentCols && row < argumentRows)
2559 {
2560 resultArray[resultIndex].cast(basicType,
2561 argumentUnionArray[col * argumentRows + row]);
2562 }
2563 else if (col == row)
2564 {
2565 resultArray[resultIndex].setFConst(1.0f);
2566 }
2567 else
2568 {
2569 resultArray[resultIndex].setFConst(0.0f);
2570 }
2571 ++resultIndex;
2572 }
2573 }
2574 ASSERT(resultIndex == resultSize);
2575 return resultArray;
2576 }
2577 }
2578
2579 for (TIntermNode *&argument : *aggregate->getSequence())
2580 {
2581 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2582 size_t argumentSize = argumentConstant->getType().getObjectSize();
2583 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2584 for (size_t i = 0u; i < argumentSize; ++i)
2585 {
2586 if (resultIndex >= resultSize)
2587 break;
2588 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2589 ++resultIndex;
2590 }
2591 }
2592 ASSERT(resultIndex == resultSize);
2593 return resultArray;
2594}
2595
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002596bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2597{
2598 switch (op)
2599 {
2600 case EOpAtan:
2601 case EOpPow:
2602 case EOpMod:
2603 case EOpMin:
2604 case EOpMax:
2605 case EOpClamp:
2606 case EOpMix:
2607 case EOpStep:
2608 case EOpSmoothStep:
2609 case EOpLdexp:
2610 case EOpMulMatrixComponentWise:
2611 case EOpOuterProduct:
2612 case EOpEqualComponentWise:
2613 case EOpNotEqualComponentWise:
2614 case EOpLessThanComponentWise:
2615 case EOpLessThanEqualComponentWise:
2616 case EOpGreaterThanComponentWise:
2617 case EOpGreaterThanEqualComponentWise:
2618 case EOpDistance:
2619 case EOpDot:
2620 case EOpCross:
2621 case EOpFaceforward:
2622 case EOpReflect:
2623 case EOpRefract:
2624 case EOpBitfieldExtract:
2625 case EOpBitfieldInsert:
2626 return true;
2627 default:
2628 return false;
2629 }
2630}
2631
Olli Etuaho1d122782015-11-06 15:35:17 +02002632// static
Olli Etuahof119a262016-08-19 15:54:22 +03002633TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2634 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302635{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002636 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002637 TIntermSequence *arguments = aggregate->getSequence();
2638 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2639 std::vector<const TConstantUnion *> unionArrays(argsCount);
2640 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002641 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302642 TBasicType basicType = EbtVoid;
2643 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002644 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302645 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002646 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2647 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302648
2649 if (i == 0)
2650 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002651 basicType = argConstant->getType().getBasicType();
2652 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302653 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002654 unionArrays[i] = argConstant->getUnionArrayPointer();
2655 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002656 if (objectSizes[i] > maxObjectSize)
2657 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302658 }
2659
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002660 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302661 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002662 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302663 if (objectSizes[i] != maxObjectSize)
2664 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2665 }
Arun Patole274f0702015-05-05 13:33:30 +05302666
Olli Etuahob43846e2015-06-02 18:18:57 +03002667 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002668
2669 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302670 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002671 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302672 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002673 ASSERT(basicType == EbtFloat);
2674 resultArray = new TConstantUnion[maxObjectSize];
2675 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302676 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002677 float y = unionArrays[0][i].getFConst();
2678 float x = unionArrays[1][i].getFConst();
2679 // Results are undefined if x and y are both 0.
2680 if (x == 0.0f && y == 0.0f)
2681 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2682 else
2683 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302684 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002685 break;
2686 }
Arun Patolebf790422015-05-18 17:53:04 +05302687
Olli Etuaho51182ab2017-01-22 00:12:29 +00002688 case EOpPow:
2689 {
2690 ASSERT(basicType == EbtFloat);
2691 resultArray = new TConstantUnion[maxObjectSize];
2692 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302693 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002694 float x = unionArrays[0][i].getFConst();
2695 float y = unionArrays[1][i].getFConst();
2696 // Results are undefined if x < 0.
2697 // Results are undefined if x = 0 and y <= 0.
2698 if (x < 0.0f)
2699 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2700 else if (x == 0.0f && y <= 0.0f)
2701 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2702 else
2703 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302704 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002705 break;
2706 }
Arun Patolebf790422015-05-18 17:53:04 +05302707
Olli Etuaho51182ab2017-01-22 00:12:29 +00002708 case EOpMod:
2709 {
2710 ASSERT(basicType == EbtFloat);
2711 resultArray = new TConstantUnion[maxObjectSize];
2712 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302713 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002714 float x = unionArrays[0][i].getFConst();
2715 float y = unionArrays[1][i].getFConst();
2716 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302717 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002718 break;
2719 }
Arun Patolebf790422015-05-18 17:53:04 +05302720
Olli Etuaho51182ab2017-01-22 00:12:29 +00002721 case EOpMin:
2722 {
2723 resultArray = new TConstantUnion[maxObjectSize];
2724 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302725 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002726 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302727 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002728 case EbtFloat:
2729 resultArray[i].setFConst(
2730 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2731 break;
2732 case EbtInt:
2733 resultArray[i].setIConst(
2734 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2735 break;
2736 case EbtUInt:
2737 resultArray[i].setUConst(
2738 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2739 break;
2740 default:
2741 UNREACHABLE();
2742 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302743 }
2744 }
2745 break;
Arun Patole274f0702015-05-05 13:33:30 +05302746 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002747
2748 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302749 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002750 resultArray = new TConstantUnion[maxObjectSize];
2751 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302752 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002753 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302754 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002755 case EbtFloat:
2756 resultArray[i].setFConst(
2757 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2758 break;
2759 case EbtInt:
2760 resultArray[i].setIConst(
2761 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2762 break;
2763 case EbtUInt:
2764 resultArray[i].setUConst(
2765 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2766 break;
2767 default:
2768 UNREACHABLE();
2769 break;
Arun Patole274f0702015-05-05 13:33:30 +05302770 }
2771 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002772 break;
Arun Patole274f0702015-05-05 13:33:30 +05302773 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002774
2775 case EOpStep:
2776 {
2777 ASSERT(basicType == EbtFloat);
2778 resultArray = new TConstantUnion[maxObjectSize];
2779 for (size_t i = 0; i < maxObjectSize; i++)
2780 resultArray[i].setFConst(
2781 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2782 break;
2783 }
2784
2785 case EOpLessThanComponentWise:
2786 {
2787 resultArray = new TConstantUnion[maxObjectSize];
2788 for (size_t i = 0; i < maxObjectSize; i++)
2789 {
2790 switch (basicType)
2791 {
2792 case EbtFloat:
2793 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2794 unionArrays[1][i].getFConst());
2795 break;
2796 case EbtInt:
2797 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2798 unionArrays[1][i].getIConst());
2799 break;
2800 case EbtUInt:
2801 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2802 unionArrays[1][i].getUConst());
2803 break;
2804 default:
2805 UNREACHABLE();
2806 break;
2807 }
2808 }
2809 break;
2810 }
2811
2812 case EOpLessThanEqualComponentWise:
2813 {
2814 resultArray = new TConstantUnion[maxObjectSize];
2815 for (size_t i = 0; i < maxObjectSize; i++)
2816 {
2817 switch (basicType)
2818 {
2819 case EbtFloat:
2820 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2821 unionArrays[1][i].getFConst());
2822 break;
2823 case EbtInt:
2824 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2825 unionArrays[1][i].getIConst());
2826 break;
2827 case EbtUInt:
2828 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2829 unionArrays[1][i].getUConst());
2830 break;
2831 default:
2832 UNREACHABLE();
2833 break;
2834 }
2835 }
2836 break;
2837 }
2838
2839 case EOpGreaterThanComponentWise:
2840 {
2841 resultArray = new TConstantUnion[maxObjectSize];
2842 for (size_t i = 0; i < maxObjectSize; i++)
2843 {
2844 switch (basicType)
2845 {
2846 case EbtFloat:
2847 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2848 unionArrays[1][i].getFConst());
2849 break;
2850 case EbtInt:
2851 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2852 unionArrays[1][i].getIConst());
2853 break;
2854 case EbtUInt:
2855 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2856 unionArrays[1][i].getUConst());
2857 break;
2858 default:
2859 UNREACHABLE();
2860 break;
2861 }
2862 }
2863 break;
2864 }
2865 case EOpGreaterThanEqualComponentWise:
2866 {
2867 resultArray = new TConstantUnion[maxObjectSize];
2868 for (size_t i = 0; i < maxObjectSize; i++)
2869 {
2870 switch (basicType)
2871 {
2872 case EbtFloat:
2873 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2874 unionArrays[1][i].getFConst());
2875 break;
2876 case EbtInt:
2877 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2878 unionArrays[1][i].getIConst());
2879 break;
2880 case EbtUInt:
2881 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2882 unionArrays[1][i].getUConst());
2883 break;
2884 default:
2885 UNREACHABLE();
2886 break;
2887 }
2888 }
2889 }
2890 break;
2891
2892 case EOpEqualComponentWise:
2893 {
2894 resultArray = new TConstantUnion[maxObjectSize];
2895 for (size_t i = 0; i < maxObjectSize; i++)
2896 {
2897 switch (basicType)
2898 {
2899 case EbtFloat:
2900 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2901 unionArrays[1][i].getFConst());
2902 break;
2903 case EbtInt:
2904 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2905 unionArrays[1][i].getIConst());
2906 break;
2907 case EbtUInt:
2908 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2909 unionArrays[1][i].getUConst());
2910 break;
2911 case EbtBool:
2912 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2913 unionArrays[1][i].getBConst());
2914 break;
2915 default:
2916 UNREACHABLE();
2917 break;
2918 }
2919 }
2920 break;
2921 }
2922
2923 case EOpNotEqualComponentWise:
2924 {
2925 resultArray = new TConstantUnion[maxObjectSize];
2926 for (size_t i = 0; i < maxObjectSize; i++)
2927 {
2928 switch (basicType)
2929 {
2930 case EbtFloat:
2931 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2932 unionArrays[1][i].getFConst());
2933 break;
2934 case EbtInt:
2935 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2936 unionArrays[1][i].getIConst());
2937 break;
2938 case EbtUInt:
2939 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2940 unionArrays[1][i].getUConst());
2941 break;
2942 case EbtBool:
2943 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2944 unionArrays[1][i].getBConst());
2945 break;
2946 default:
2947 UNREACHABLE();
2948 break;
2949 }
2950 }
2951 break;
2952 }
2953
2954 case EOpDistance:
2955 {
2956 ASSERT(basicType == EbtFloat);
2957 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2958 resultArray = new TConstantUnion();
2959 for (size_t i = 0; i < maxObjectSize; i++)
2960 {
2961 float x = unionArrays[0][i].getFConst();
2962 float y = unionArrays[1][i].getFConst();
2963 distanceArray[i].setFConst(x - y);
2964 }
2965 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2966 break;
2967 }
2968
2969 case EOpDot:
2970 ASSERT(basicType == EbtFloat);
2971 resultArray = new TConstantUnion();
2972 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2973 break;
2974
2975 case EOpCross:
2976 {
2977 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2978 resultArray = new TConstantUnion[maxObjectSize];
2979 float x0 = unionArrays[0][0].getFConst();
2980 float x1 = unionArrays[0][1].getFConst();
2981 float x2 = unionArrays[0][2].getFConst();
2982 float y0 = unionArrays[1][0].getFConst();
2983 float y1 = unionArrays[1][1].getFConst();
2984 float y2 = unionArrays[1][2].getFConst();
2985 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2986 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2987 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2988 break;
2989 }
2990
2991 case EOpReflect:
2992 {
2993 ASSERT(basicType == EbtFloat);
2994 // genType reflect (genType I, genType N) :
2995 // For the incident vector I and surface orientation N, returns the reflection
2996 // direction:
2997 // I - 2 * dot(N, I) * N.
2998 resultArray = new TConstantUnion[maxObjectSize];
2999 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3000 for (size_t i = 0; i < maxObjectSize; i++)
3001 {
3002 float result = unionArrays[0][i].getFConst() -
3003 2.0f * dotProduct * unionArrays[1][i].getFConst();
3004 resultArray[i].setFConst(result);
3005 }
3006 break;
3007 }
3008
3009 case EOpMulMatrixComponentWise:
3010 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003011 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3012 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003013 // Perform component-wise matrix multiplication.
3014 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003015 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003016 angle::Matrix<float> result =
3017 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3018 SetUnionArrayFromMatrix(result, resultArray);
3019 break;
3020 }
3021
3022 case EOpOuterProduct:
3023 {
3024 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003025 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3026 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003027 resultArray = new TConstantUnion[numRows * numCols];
3028 angle::Matrix<float> result =
3029 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3030 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3031 SetUnionArrayFromMatrix(result, resultArray);
3032 break;
3033 }
3034
3035 case EOpClamp:
3036 {
3037 resultArray = new TConstantUnion[maxObjectSize];
3038 for (size_t i = 0; i < maxObjectSize; i++)
3039 {
3040 switch (basicType)
3041 {
3042 case EbtFloat:
3043 {
3044 float x = unionArrays[0][i].getFConst();
3045 float min = unionArrays[1][i].getFConst();
3046 float max = unionArrays[2][i].getFConst();
3047 // Results are undefined if min > max.
3048 if (min > max)
3049 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3050 &resultArray[i]);
3051 else
3052 resultArray[i].setFConst(gl::clamp(x, min, max));
3053 break;
3054 }
3055
3056 case EbtInt:
3057 {
3058 int x = unionArrays[0][i].getIConst();
3059 int min = unionArrays[1][i].getIConst();
3060 int max = unionArrays[2][i].getIConst();
3061 // Results are undefined if min > max.
3062 if (min > max)
3063 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3064 &resultArray[i]);
3065 else
3066 resultArray[i].setIConst(gl::clamp(x, min, max));
3067 break;
3068 }
3069 case EbtUInt:
3070 {
3071 unsigned int x = unionArrays[0][i].getUConst();
3072 unsigned int min = unionArrays[1][i].getUConst();
3073 unsigned int max = unionArrays[2][i].getUConst();
3074 // Results are undefined if min > max.
3075 if (min > max)
3076 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3077 &resultArray[i]);
3078 else
3079 resultArray[i].setUConst(gl::clamp(x, min, max));
3080 break;
3081 }
3082 default:
3083 UNREACHABLE();
3084 break;
3085 }
3086 }
3087 break;
3088 }
3089
3090 case EOpMix:
3091 {
3092 ASSERT(basicType == EbtFloat);
3093 resultArray = new TConstantUnion[maxObjectSize];
3094 for (size_t i = 0; i < maxObjectSize; i++)
3095 {
3096 float x = unionArrays[0][i].getFConst();
3097 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003098 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003099 if (type == EbtFloat)
3100 {
3101 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3102 float a = unionArrays[2][i].getFConst();
3103 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3104 }
3105 else // 3rd parameter is EbtBool
3106 {
3107 ASSERT(type == EbtBool);
3108 // Selects which vector each returned component comes from.
3109 // For a component of a that is false, the corresponding component of x is
3110 // returned.
3111 // For a component of a that is true, the corresponding component of y is
3112 // returned.
3113 bool a = unionArrays[2][i].getBConst();
3114 resultArray[i].setFConst(a ? y : x);
3115 }
3116 }
3117 break;
3118 }
3119
3120 case EOpSmoothStep:
3121 {
3122 ASSERT(basicType == EbtFloat);
3123 resultArray = new TConstantUnion[maxObjectSize];
3124 for (size_t i = 0; i < maxObjectSize; i++)
3125 {
3126 float edge0 = unionArrays[0][i].getFConst();
3127 float edge1 = unionArrays[1][i].getFConst();
3128 float x = unionArrays[2][i].getFConst();
3129 // Results are undefined if edge0 >= edge1.
3130 if (edge0 >= edge1)
3131 {
3132 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3133 }
3134 else
3135 {
3136 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3137 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3138 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3139 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3140 }
3141 }
3142 break;
3143 }
3144
Olli Etuaho74da73f2017-02-01 15:37:48 +00003145 case EOpLdexp:
3146 {
3147 resultArray = new TConstantUnion[maxObjectSize];
3148 for (size_t i = 0; i < maxObjectSize; i++)
3149 {
3150 float x = unionArrays[0][i].getFConst();
3151 int exp = unionArrays[1][i].getIConst();
3152 if (exp > 128)
3153 {
3154 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3155 }
3156 else
3157 {
3158 resultArray[i].setFConst(gl::Ldexp(x, exp));
3159 }
3160 }
3161 break;
3162 }
3163
Jamie Madille72595b2017-06-06 15:12:26 -04003164 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003165 {
3166 ASSERT(basicType == EbtFloat);
3167 // genType faceforward(genType N, genType I, genType Nref) :
3168 // If dot(Nref, I) < 0 return N, otherwise return -N.
3169 resultArray = new TConstantUnion[maxObjectSize];
3170 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3171 for (size_t i = 0; i < maxObjectSize; i++)
3172 {
3173 if (dotProduct < 0)
3174 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3175 else
3176 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3177 }
3178 break;
3179 }
3180
3181 case EOpRefract:
3182 {
3183 ASSERT(basicType == EbtFloat);
3184 // genType refract(genType I, genType N, float eta) :
3185 // For the incident vector I and surface normal N, and the ratio of indices of
3186 // refraction eta,
3187 // return the refraction vector. The result is computed by
3188 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3189 // if (k < 0.0)
3190 // return genType(0.0)
3191 // else
3192 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3193 resultArray = new TConstantUnion[maxObjectSize];
3194 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3195 for (size_t i = 0; i < maxObjectSize; i++)
3196 {
3197 float eta = unionArrays[2][i].getFConst();
3198 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3199 if (k < 0.0f)
3200 resultArray[i].setFConst(0.0f);
3201 else
3202 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3203 (eta * dotProduct + sqrtf(k)) *
3204 unionArrays[1][i].getFConst());
3205 }
3206 break;
3207 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003208 case EOpBitfieldExtract:
3209 {
3210 resultArray = new TConstantUnion[maxObjectSize];
3211 for (size_t i = 0; i < maxObjectSize; ++i)
3212 {
3213 int offset = unionArrays[1][0].getIConst();
3214 int bits = unionArrays[2][0].getIConst();
3215 if (bits == 0)
3216 {
3217 if (aggregate->getBasicType() == EbtInt)
3218 {
3219 resultArray[i].setIConst(0);
3220 }
3221 else
3222 {
3223 ASSERT(aggregate->getBasicType() == EbtUInt);
3224 resultArray[i].setUConst(0);
3225 }
3226 }
3227 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3228 {
3229 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3230 &resultArray[i]);
3231 }
3232 else
3233 {
3234 // bits can be 32 here, so we need to avoid bit shift overflow.
3235 uint32_t maskMsb = 1u << (bits - 1);
3236 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3237 if (aggregate->getBasicType() == EbtInt)
3238 {
3239 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3240 uint32_t resultUnsigned = (value & mask) >> offset;
3241 if ((resultUnsigned & maskMsb) != 0)
3242 {
3243 // The most significant bits (from bits+1 to the most significant bit)
3244 // should be set to 1.
3245 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3246 resultUnsigned |= higherBitsMask;
3247 }
3248 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3249 }
3250 else
3251 {
3252 ASSERT(aggregate->getBasicType() == EbtUInt);
3253 uint32_t value = unionArrays[0][i].getUConst();
3254 resultArray[i].setUConst((value & mask) >> offset);
3255 }
3256 }
3257 }
3258 break;
3259 }
3260 case EOpBitfieldInsert:
3261 {
3262 resultArray = new TConstantUnion[maxObjectSize];
3263 for (size_t i = 0; i < maxObjectSize; ++i)
3264 {
3265 int offset = unionArrays[2][0].getIConst();
3266 int bits = unionArrays[3][0].getIConst();
3267 if (bits == 0)
3268 {
3269 if (aggregate->getBasicType() == EbtInt)
3270 {
3271 int32_t base = unionArrays[0][i].getIConst();
3272 resultArray[i].setIConst(base);
3273 }
3274 else
3275 {
3276 ASSERT(aggregate->getBasicType() == EbtUInt);
3277 uint32_t base = unionArrays[0][i].getUConst();
3278 resultArray[i].setUConst(base);
3279 }
3280 }
3281 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3282 {
3283 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3284 &resultArray[i]);
3285 }
3286 else
3287 {
3288 // bits can be 32 here, so we need to avoid bit shift overflow.
3289 uint32_t maskMsb = 1u << (bits - 1);
3290 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3291 uint32_t baseMask = ~insertMask;
3292 if (aggregate->getBasicType() == EbtInt)
3293 {
3294 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3295 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3296 uint32_t resultUnsigned =
3297 (base & baseMask) | ((insert << offset) & insertMask);
3298 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3299 }
3300 else
3301 {
3302 ASSERT(aggregate->getBasicType() == EbtUInt);
3303 uint32_t base = unionArrays[0][i].getUConst();
3304 uint32_t insert = unionArrays[1][i].getUConst();
3305 resultArray[i].setUConst((base & baseMask) |
3306 ((insert << offset) & insertMask));
3307 }
3308 }
3309 }
3310 break;
3311 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003312
3313 default:
3314 UNREACHABLE();
3315 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303316 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003317 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303318}
3319
Jamie Madill45bcc782016-11-07 13:58:48 -05003320} // namespace sh