blob: 2d3c14e3fb0818f3a80354c56997f72aa213aec4 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040021#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040023#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040024
Jamie Madill45bcc782016-11-07 13:58:48 -050025namespace sh
26{
27
Jamie Madillb1a85f42014-08-19 15:23:24 -040028namespace
29{
30
Jamie Madilld7b1ab52016-12-12 14:42:19 -050031const float kPi = 3.14159265358979323846f;
Arun Patole9dea48f2015-04-02 11:45:09 +053032const float kDegreesToRadiansMultiplier = kPi / 180.0f;
33const float kRadiansToDegreesMultiplier = 180.0f / kPi;
34
Jamie Madillb1a85f42014-08-19 15:23:24 -040035TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
36{
37 return left > right ? left : right;
38}
39
Arun Patole274f0702015-05-05 13:33:30 +053040TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
41{
42 TConstantUnion *constUnion = new TConstantUnion[size];
43 for (unsigned int i = 0; i < size; ++i)
Jamie Madilld7b1ab52016-12-12 14:42:19 -050044 constUnion[i] = constant;
Arun Patole274f0702015-05-05 13:33:30 +053045
46 return constUnion;
47}
48
Olli Etuahof119a262016-08-19 15:54:22 +030049void UndefinedConstantFoldingError(const TSourceLoc &loc,
50 TOperator op,
51 TBasicType basicType,
52 TDiagnostics *diagnostics,
53 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053054{
Olli Etuahof119a262016-08-19 15:54:22 +030055 diagnostics->warning(loc, "operation result is undefined for the values passed in",
Olli Etuaho4de340a2016-12-16 09:32:03 +000056 GetOperatorString(op));
Arun Patolebf790422015-05-18 17:53:04 +053057
58 switch (basicType)
59 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050060 case EbtFloat:
61 result->setFConst(0.0f);
62 break;
63 case EbtInt:
64 result->setIConst(0);
65 break;
66 case EbtUInt:
67 result->setUConst(0u);
68 break;
69 case EbtBool:
70 result->setBConst(false);
71 break;
72 default:
73 break;
Arun Patolebf790422015-05-18 17:53:04 +053074 }
75}
76
Olli Etuaho5c0e0232015-11-11 15:55:59 +020077float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053078{
79 float result = 0.0f;
80 for (size_t i = 0; i < paramArraySize; i++)
81 {
82 float f = paramArray[i].getFConst();
83 result += f * f;
84 }
85 return sqrtf(result);
86}
87
Olli Etuaho5c0e0232015-11-11 15:55:59 +020088float VectorDotProduct(const TConstantUnion *paramArray1,
89 const TConstantUnion *paramArray2,
90 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053091{
92 float result = 0.0f;
93 for (size_t i = 0; i < paramArraySize; i++)
94 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
95 return result;
96}
97
Olli Etuaho2768bc82017-12-12 11:51:48 +020098TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray, const TIntermTyped *originalNode)
Olli Etuahob43846e2015-06-02 18:18:57 +030099{
Olli Etuaho2768bc82017-12-12 11:51:48 +0200100 ASSERT(constArray != nullptr);
101 // Note that we inherit whatever qualifier the folded node had. Nodes may be constant folded
102 // without being qualified as constant.
Olli Etuahob43846e2015-06-02 18:18:57 +0300103 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuahob43846e2015-06-02 18:18:57 +0300104 folded->setLine(originalNode->getLine());
105 return folded;
106}
107
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200108angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
109 const unsigned int &rows,
110 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530111{
112 std::vector<float> elements;
113 for (size_t i = 0; i < rows * cols; i++)
114 elements.push_back(paramArray[i].getFConst());
115 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300116 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
117 // so that the created matrix will have the expected dimensions after the transpose.
118 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530119}
120
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200121angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530122{
123 std::vector<float> elements;
124 for (size_t i = 0; i < size * size; i++)
125 elements.push_back(paramArray[i].getFConst());
126 // Transpose is used since the Matrix constructor expects arguments in row-major order,
127 // whereas the paramArray is in column-major order.
128 return angle::Matrix<float>(elements, size).transpose();
129}
130
131void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
132{
133 // Transpose is used since the input Matrix is in row-major order,
134 // whereas the actual result should be in column-major order.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500135 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530136 std::vector<float> resultElements = result.elements();
137 for (size_t i = 0; i < resultElements.size(); i++)
138 resultArray[i].setFConst(resultElements[i]);
139}
140
Jamie Madillb1a85f42014-08-19 15:23:24 -0400141} // namespace anonymous
142
Olli Etuahobed35d72017-12-20 16:36:26 +0200143TName::TName(const TString &name) : mName(name), mIsInternal(false)
Olli Etuahoae4dbf32017-12-08 20:49:00 +0100144{
145}
146
Olli Etuaho1bb85282017-12-14 13:39:53 +0200147TName::TName(const TSymbol *symbol)
Olli Etuahobed35d72017-12-20 16:36:26 +0200148 : mName(symbol->symbolType() == SymbolType::Empty ? "" : symbol->name()),
149 mIsInternal(symbol->symbolType() == SymbolType::AngleInternal)
Olli Etuaho1bb85282017-12-14 13:39:53 +0200150{
151}
152
Jamie Madillb1a85f42014-08-19 15:23:24 -0400153////////////////////////////////////////////////////////////////
154//
155// Member functions of the nodes used for building the tree.
156//
157////////////////////////////////////////////////////////////////
158
Olli Etuahod2a67b92014-10-21 16:42:57 +0300159void TIntermTyped::setTypePreservePrecision(const TType &t)
160{
161 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500162 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300163 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
164 mType.setPrecision(precision);
165}
166
Jamie Madillb1a85f42014-08-19 15:23:24 -0400167#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500168 if (node == original) \
169 { \
170 node = static_cast<type *>(replacement); \
171 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400172 }
173
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500174bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400175{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300176 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400177 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
178 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
179 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100180 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400181 return false;
182}
183
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500184bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400185{
186 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
187 return false;
188}
189
Olli Etuahob6fa0432016-09-28 16:28:05 +0100190bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
191{
192 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
193 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
194 return false;
195}
196
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500197bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400198{
199 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
200 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
201 return false;
202}
203
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500204bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400205{
Olli Etuahoa2234302016-08-31 12:05:39 +0300206 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400207 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
208 return false;
209}
210
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000211bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
212{
213 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
214 return false;
215}
216
Olli Etuaho336b1472016-10-05 16:37:55 +0100217bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
218{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000219 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100220 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
221 return false;
222}
223
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500224bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400225{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100226 return replaceChildNodeInternal(original, replacement);
227}
228
229bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
230{
231 return replaceChildNodeInternal(original, replacement);
232}
233
Olli Etuaho16c745a2017-01-16 17:02:27 +0000234bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
235{
236 return replaceChildNodeInternal(original, replacement);
237}
238
Olli Etuaho13389b62016-10-16 11:48:18 +0100239bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
240{
241 return replaceChildNodeInternal(original, replacement);
242}
243
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100244bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
245{
246 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400247 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100248 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400249 }
250 return false;
251}
252
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100253bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
254 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300255{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100256 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300257 {
258 if (*it == original)
259 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100260 it = getSequence()->erase(it);
261 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300262 return true;
263 }
264 }
265 return false;
266}
267
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100268bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
269 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300270{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100271 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300272 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300273 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300274 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100275 auto it = getSequence()->begin() + position;
276 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300277 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300278}
279
Olli Etuaho195be942017-12-04 23:40:14 +0200280TIntermSymbol::TIntermSymbol(const TVariable *variable)
Olli Etuahobed35d72017-12-20 16:36:26 +0200281 : TIntermTyped(variable->getType()), mVariable(variable), mSymbol(variable)
Olli Etuaho195be942017-12-04 23:40:14 +0200282{
Olli Etuaho195be942017-12-04 23:40:14 +0200283}
284
Olli Etuahob6af22b2017-12-15 14:05:44 +0200285const TSymbolUniqueId &TIntermSymbol::uniqueId() const
286{
287 return mVariable->uniqueId();
288}
289
Olli Etuahofe486322017-03-21 09:30:54 +0000290TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
291 TIntermSequence *arguments)
292{
Olli Etuaho0c371002017-12-13 17:00:25 +0400293 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000294}
295
Olli Etuaho0c371002017-12-13 17:00:25 +0400296TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
297 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000298{
Olli Etuaho0c371002017-12-13 17:00:25 +0400299 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000300}
301
302TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
303 TIntermSequence *arguments)
304{
305 TIntermAggregate *callNode =
Olli Etuaho0c371002017-12-13 17:00:25 +0400306 new TIntermAggregate(&func, func.getReturnType(), EOpCallBuiltInFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000307 // Note that name needs to be set before texture function type is determined.
308 callNode->setBuiltInFunctionPrecision();
309 return callNode;
310}
311
312TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000313 TIntermSequence *arguments)
314{
Olli Etuaho0c371002017-12-13 17:00:25 +0400315 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000316}
317
318TIntermAggregate *TIntermAggregate::Create(const TType &type,
319 TOperator op,
320 TIntermSequence *arguments)
321{
Olli Etuahofe486322017-03-21 09:30:54 +0000322 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400323 ASSERT(op != EOpCallInternalRawFunction); // Should use CreateRawFunctionCall
Olli Etuahofe486322017-03-21 09:30:54 +0000324 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400325 ASSERT(op != EOpConstruct); // Should use CreateConstructor
326 return new TIntermAggregate(nullptr, type, op, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000327}
328
Olli Etuaho0c371002017-12-13 17:00:25 +0400329TIntermAggregate::TIntermAggregate(const TFunction *func,
330 const TType &type,
331 TOperator op,
332 TIntermSequence *arguments)
333 : TIntermOperator(op),
334 mUseEmulatedFunction(false),
335 mGotPrecisionFromChildren(false),
336 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800337{
338 if (arguments != nullptr)
339 {
340 mArguments.swap(*arguments);
341 }
Olli Etuaho1bb85282017-12-14 13:39:53 +0200342 ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800343 setTypePrecisionAndQualifier(type);
344}
345
346void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
347{
348 setType(type);
349 mType.setQualifier(EvqTemporary);
350 if (!isFunctionCall())
351 {
352 if (isConstructor())
353 {
354 // Structs should not be precision qualified, the individual members may be.
355 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300356 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800357 {
358 setPrecisionFromChildren();
359 }
360 }
361 else
362 {
363 setPrecisionForBuiltInOp();
364 }
365 if (areChildrenConstQualified())
366 {
367 mType.setQualifier(EvqConst);
368 }
369 }
370}
371
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200372bool TIntermAggregate::areChildrenConstQualified()
373{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800374 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200375 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800376 TIntermTyped *typedArg = arg->getAsTyped();
377 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200378 {
379 return false;
380 }
381 }
382 return true;
383}
384
Olli Etuahod2a67b92014-10-21 16:42:57 +0300385void TIntermAggregate::setPrecisionFromChildren()
386{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300387 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300388 if (getBasicType() == EbtBool)
389 {
390 mType.setPrecision(EbpUndefined);
391 return;
392 }
393
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500394 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800395 TIntermSequence::iterator childIter = mArguments.begin();
396 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300397 {
398 TIntermTyped *typed = (*childIter)->getAsTyped();
399 if (typed)
400 precision = GetHigherPrecision(typed->getPrecision(), precision);
401 ++childIter;
402 }
403 mType.setPrecision(precision);
404}
405
Olli Etuaho9250cb22017-01-21 10:51:27 +0000406void TIntermAggregate::setPrecisionForBuiltInOp()
407{
408 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800409 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000410 if (!setPrecisionForSpecialBuiltInOp())
411 {
412 setPrecisionFromChildren();
413 }
414}
415
416bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
417{
418 switch (mOp)
419 {
420 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800421 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
422 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000423 return true;
424 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800425 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
426 mArguments[1]->getAsTyped()->getPrecision()));
427 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000428 return true;
429 case EOpUaddCarry:
430 case EOpUsubBorrow:
431 mType.setPrecision(EbpHigh);
432 return true;
433 default:
434 return false;
435 }
436}
437
Olli Etuahod2a67b92014-10-21 16:42:57 +0300438void TIntermAggregate::setBuiltInFunctionPrecision()
439{
440 // All built-ins returning bool should be handled as ops, not functions.
441 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800442 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300443
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800444 TPrecision precision = EbpUndefined;
445 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300446 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800447 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300448 // ESSL spec section 8: texture functions get their precision from the sampler.
449 if (typed && IsSampler(typed->getBasicType()))
450 {
451 precision = typed->getPrecision();
452 break;
453 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300454 }
455 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
456 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobed35d72017-12-20 16:36:26 +0200457 if (mFunction->name().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300458 mType.setPrecision(EbpHigh);
459 else
460 mType.setPrecision(precision);
461}
462
Olli Etuahof2209f72017-04-01 12:45:55 +0300463TString TIntermAggregate::getSymbolTableMangledName() const
464{
465 ASSERT(!isConstructor());
466 switch (mOp)
467 {
468 case EOpCallInternalRawFunction:
469 case EOpCallBuiltInFunction:
470 case EOpCallFunctionInAST:
Olli Etuahobed35d72017-12-20 16:36:26 +0200471 return TFunction::GetMangledNameFromCall(mFunction->name(), mArguments);
Olli Etuahof2209f72017-04-01 12:45:55 +0300472 default:
473 TString opString = GetOperatorString(mOp);
474 return TFunction::GetMangledNameFromCall(opString, mArguments);
475 }
476}
477
Olli Etuaho0c371002017-12-13 17:00:25 +0400478const char *TIntermAggregate::functionName() const
479{
480 ASSERT(!isConstructor());
481 switch (mOp)
482 {
483 case EOpCallInternalRawFunction:
484 case EOpCallBuiltInFunction:
485 case EOpCallFunctionInAST:
Olli Etuahobed35d72017-12-20 16:36:26 +0200486 return mFunction->name().c_str();
Olli Etuaho0c371002017-12-13 17:00:25 +0400487 default:
488 return GetOperatorString(mOp);
489 }
490}
491
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300492bool TIntermAggregate::hasSideEffects() const
493{
Olli Etuaho0c371002017-12-13 17:00:25 +0400494 if (isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300495 {
496 for (TIntermNode *arg : mArguments)
497 {
498 if (arg->getAsTyped()->hasSideEffects())
499 {
500 return true;
501 }
502 }
503 return false;
504 }
505 // Conservatively assume most aggregate operators have side-effects
506 return true;
507}
508
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100509void TIntermBlock::appendStatement(TIntermNode *statement)
510{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300511 // Declaration nodes with no children can appear if it was an empty declaration or if all the
512 // declarators just added constants to the symbol table instead of generating code. We still
513 // need to add the declaration to the AST in that case because it might be relevant to the
514 // validity of switch/case.
515 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100516 {
517 mStatements.push_back(statement);
518 }
519}
520
Olli Etuaho16c745a2017-01-16 17:02:27 +0000521void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
522{
523 ASSERT(parameter != nullptr);
524 mParameters.push_back(parameter);
525}
526
Olli Etuaho13389b62016-10-16 11:48:18 +0100527void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
528{
529 ASSERT(declarator != nullptr);
530 ASSERT(declarator->getAsSymbolNode() != nullptr ||
531 (declarator->getAsBinaryNode() != nullptr &&
532 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
533 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300534 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100535 mDeclarators.push_back(declarator);
536}
537
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300538bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
539{
540 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
541 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
542 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
543 return false;
544}
545
Olli Etuaho57961272016-09-14 13:57:46 +0300546bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400547{
548 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100549 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
550 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400551 return false;
552}
553
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500554bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200555{
556 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100557 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300558 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200559 return false;
560}
561
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500562bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200563{
564 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
565 return false;
566}
567
Olli Etuahod7a25242015-08-18 13:49:45 +0300568TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
569{
570 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
571 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
572 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
573 mLine = node.mLine;
574}
575
Olli Etuahod4f4c112016-04-15 15:11:24 +0300576bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
577{
578 TIntermAggregate *constructor = getAsAggregate();
579 if (!constructor || !constructor->isConstructor())
580 {
581 return false;
582 }
583 for (TIntermNode *&node : *constructor->getSequence())
584 {
585 if (!node->getAsConstantUnion())
586 return false;
587 }
588 return true;
589}
590
Olli Etuahod7a25242015-08-18 13:49:45 +0300591TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
592{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200593 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300594}
595
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200596TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
597 : TIntermTyped(function->getReturnType()), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100598{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200599 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100600}
601
Olli Etuahod7a25242015-08-18 13:49:45 +0300602TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
603 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300604 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100605 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400606 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300607{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800608 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300609 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800610 TIntermTyped *typedArg = arg->getAsTyped();
611 ASSERT(typedArg != nullptr);
612 TIntermTyped *argCopy = typedArg->deepCopy();
613 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300614 }
615}
616
Olli Etuahofe486322017-03-21 09:30:54 +0000617TIntermAggregate *TIntermAggregate::shallowCopy() const
618{
619 TIntermSequence *copySeq = new TIntermSequence();
620 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400621 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000622 copyNode->setLine(mLine);
623 return copyNode;
624}
625
Olli Etuahob6fa0432016-09-28 16:28:05 +0100626TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
627{
628 TIntermTyped *operandCopy = node.mOperand->deepCopy();
629 ASSERT(operandCopy != nullptr);
630 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000631 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100632}
633
Olli Etuahod7a25242015-08-18 13:49:45 +0300634TIntermBinary::TIntermBinary(const TIntermBinary &node)
635 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
636{
637 TIntermTyped *leftCopy = node.mLeft->deepCopy();
638 TIntermTyped *rightCopy = node.mRight->deepCopy();
639 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
640 mLeft = leftCopy;
641 mRight = rightCopy;
642}
643
644TIntermUnary::TIntermUnary(const TIntermUnary &node)
645 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
646{
647 TIntermTyped *operandCopy = node.mOperand->deepCopy();
648 ASSERT(operandCopy != nullptr);
649 mOperand = operandCopy;
650}
651
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300652TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300653{
Olli Etuahod7a25242015-08-18 13:49:45 +0300654 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300655 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
656 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300657 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300658 mCondition = conditionCopy;
659 mTrueExpression = trueCopy;
660 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300661}
662
Jamie Madillb1a85f42014-08-19 15:23:24 -0400663bool TIntermOperator::isAssignment() const
664{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300665 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400666}
667
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300668bool TIntermOperator::isMultiplication() const
669{
670 switch (mOp)
671 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500672 case EOpMul:
673 case EOpMatrixTimesMatrix:
674 case EOpMatrixTimesVector:
675 case EOpMatrixTimesScalar:
676 case EOpVectorTimesMatrix:
677 case EOpVectorTimesScalar:
678 return true;
679 default:
680 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300681 }
682}
683
Jamie Madillb1a85f42014-08-19 15:23:24 -0400684bool TIntermOperator::isConstructor() const
685{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300686 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400687}
688
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800689bool TIntermOperator::isFunctionCall() const
690{
691 switch (mOp)
692 {
693 case EOpCallFunctionInAST:
694 case EOpCallBuiltInFunction:
695 case EOpCallInternalRawFunction:
696 return true;
697 default:
698 return false;
699 }
700}
701
Olli Etuaho1dded802016-08-18 18:13:13 +0300702TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
703{
704 if (left.isMatrix())
705 {
706 if (right.isMatrix())
707 {
708 return EOpMatrixTimesMatrix;
709 }
710 else
711 {
712 if (right.isVector())
713 {
714 return EOpMatrixTimesVector;
715 }
716 else
717 {
718 return EOpMatrixTimesScalar;
719 }
720 }
721 }
722 else
723 {
724 if (right.isMatrix())
725 {
726 if (left.isVector())
727 {
728 return EOpVectorTimesMatrix;
729 }
730 else
731 {
732 return EOpMatrixTimesScalar;
733 }
734 }
735 else
736 {
737 // Neither operand is a matrix.
738 if (left.isVector() == right.isVector())
739 {
740 // Leave as component product.
741 return EOpMul;
742 }
743 else
744 {
745 return EOpVectorTimesScalar;
746 }
747 }
748 }
749}
750
751TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
752{
753 if (left.isMatrix())
754 {
755 if (right.isMatrix())
756 {
757 return EOpMatrixTimesMatrixAssign;
758 }
759 else
760 {
761 // right should be scalar, but this may not be validated yet.
762 return EOpMatrixTimesScalarAssign;
763 }
764 }
765 else
766 {
767 if (right.isMatrix())
768 {
769 // Left should be a vector, but this may not be validated yet.
770 return EOpVectorTimesMatrixAssign;
771 }
772 else
773 {
774 // Neither operand is a matrix.
775 if (left.isVector() == right.isVector())
776 {
777 // Leave as component product.
778 return EOpMulAssign;
779 }
780 else
781 {
782 // left should be vector and right should be scalar, but this may not be validated
783 // yet.
784 return EOpVectorTimesScalarAssign;
785 }
786 }
787 }
788}
789
Jamie Madillb1a85f42014-08-19 15:23:24 -0400790//
791// Make sure the type of a unary operator is appropriate for its
792// combination of operation and operand type.
793//
Olli Etuahoa2234302016-08-31 12:05:39 +0300794void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400795{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300796 if (mOp == EOpArrayLength)
797 {
798 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
799 setType(TType(EbtInt, EbpUndefined, EvqConst));
800 return;
801 }
802
Olli Etuahoa2234302016-08-31 12:05:39 +0300803 TQualifier resultQualifier = EvqTemporary;
804 if (mOperand->getQualifier() == EvqConst)
805 resultQualifier = EvqConst;
806
807 unsigned char operandPrimarySize =
808 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400809 switch (mOp)
810 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300811 case EOpFloatBitsToInt:
812 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
813 break;
814 case EOpFloatBitsToUint:
815 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
816 break;
817 case EOpIntBitsToFloat:
818 case EOpUintBitsToFloat:
819 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
820 break;
821 case EOpPackSnorm2x16:
822 case EOpPackUnorm2x16:
823 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800824 case EOpPackUnorm4x8:
825 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300826 setType(TType(EbtUInt, EbpHigh, resultQualifier));
827 break;
828 case EOpUnpackSnorm2x16:
829 case EOpUnpackUnorm2x16:
830 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
831 break;
832 case EOpUnpackHalf2x16:
833 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
834 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800835 case EOpUnpackUnorm4x8:
836 case EOpUnpackSnorm4x8:
837 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
838 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300839 case EOpAny:
840 case EOpAll:
841 setType(TType(EbtBool, EbpUndefined, resultQualifier));
842 break;
843 case EOpLength:
844 case EOpDeterminant:
845 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
846 break;
847 case EOpTranspose:
848 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
849 static_cast<unsigned char>(mOperand->getType().getRows()),
850 static_cast<unsigned char>(mOperand->getType().getCols())));
851 break;
852 case EOpIsInf:
853 case EOpIsNan:
854 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
855 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000856 case EOpBitfieldReverse:
857 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
858 break;
859 case EOpBitCount:
860 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
861 break;
862 case EOpFindLSB:
863 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
864 break;
865 case EOpFindMSB:
866 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
867 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300868 default:
869 setType(mOperand->getType());
870 mType.setQualifier(resultQualifier);
871 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400872 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300873}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400874
Olli Etuahob6fa0432016-09-28 16:28:05 +0100875TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
876 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
877 mOperand(operand),
878 mSwizzleOffsets(swizzleOffsets)
879{
880 ASSERT(mSwizzleOffsets.size() <= 4);
881 promote();
882}
883
Olli Etuahoa2234302016-08-31 12:05:39 +0300884TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
885 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
886{
887 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400888}
889
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300890TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
891 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
892{
893 promote();
894}
895
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000896TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
897 : TIntermNode(), mSymbol(symbol)
898{
899 ASSERT(symbol);
900 setLine(line);
901}
902
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300903TIntermTernary::TIntermTernary(TIntermTyped *cond,
904 TIntermTyped *trueExpression,
905 TIntermTyped *falseExpression)
906 : TIntermTyped(trueExpression->getType()),
907 mCondition(cond),
908 mTrueExpression(trueExpression),
909 mFalseExpression(falseExpression)
910{
911 getTypePointer()->setQualifier(
912 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
913}
914
Olli Etuaho81629262017-04-19 11:56:01 +0300915TIntermLoop::TIntermLoop(TLoopType type,
916 TIntermNode *init,
917 TIntermTyped *cond,
918 TIntermTyped *expr,
919 TIntermBlock *body)
920 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
921{
922 // Declaration nodes with no children can appear if all the declarators just added constants to
923 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
924 if (mInit && mInit->getAsDeclarationNode() &&
925 mInit->getAsDeclarationNode()->getSequence()->empty())
926 {
927 mInit = nullptr;
928 }
929}
930
Olli Etuaho923ecef2017-10-11 12:01:38 +0300931TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
932 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
933{
934 // Prune empty false blocks so that there won't be unnecessary operations done on it.
935 if (mFalseBlock && mFalseBlock->getSequence()->empty())
936 {
937 mFalseBlock = nullptr;
938 }
939}
940
941TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
942 : TIntermNode(), mInit(init), mStatementList(statementList)
943{
944 ASSERT(mStatementList);
945}
946
947void TIntermSwitch::setStatementList(TIntermBlock *statementList)
948{
949 ASSERT(statementList);
950 mStatementList = statementList;
951}
952
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300953// static
954TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
955 TIntermTyped *trueExpression,
956 TIntermTyped *falseExpression)
957{
958 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
959 falseExpression->getQualifier() == EvqConst)
960 {
961 return EvqConst;
962 }
963 return EvqTemporary;
964}
965
Olli Etuahoeb7f90f2017-07-07 17:25:23 +0300966TIntermTyped *TIntermTernary::fold()
967{
968 if (mCondition->getAsConstantUnion())
969 {
970 if (mCondition->getAsConstantUnion()->getBConst(0))
971 {
972 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
973 return mTrueExpression;
974 }
975 else
976 {
977 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
978 return mFalseExpression;
979 }
980 }
981 return this;
982}
983
Olli Etuahob6fa0432016-09-28 16:28:05 +0100984void TIntermSwizzle::promote()
985{
986 TQualifier resultQualifier = EvqTemporary;
987 if (mOperand->getQualifier() == EvqConst)
988 resultQualifier = EvqConst;
989
990 auto numFields = mSwizzleOffsets.size();
991 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
992 static_cast<unsigned char>(numFields)));
993}
994
995bool TIntermSwizzle::hasDuplicateOffsets() const
996{
997 int offsetCount[4] = {0u, 0u, 0u, 0u};
998 for (const auto offset : mSwizzleOffsets)
999 {
1000 offsetCount[offset]++;
1001 if (offsetCount[offset] > 1)
1002 {
1003 return true;
1004 }
1005 }
1006 return false;
1007}
1008
Olli Etuaho09b04a22016-12-15 13:30:26 +00001009bool TIntermSwizzle::offsetsMatch(int offset) const
1010{
1011 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1012}
1013
Olli Etuahob6fa0432016-09-28 16:28:05 +01001014void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1015{
1016 for (const int offset : mSwizzleOffsets)
1017 {
1018 switch (offset)
1019 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001020 case 0:
1021 *out << "x";
1022 break;
1023 case 1:
1024 *out << "y";
1025 break;
1026 case 2:
1027 *out << "z";
1028 break;
1029 case 3:
1030 *out << "w";
1031 break;
1032 default:
1033 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001034 }
1035 }
1036}
1037
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001038TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1039 const TIntermTyped *left,
1040 const TIntermTyped *right)
1041{
1042 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1043 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1044 right->getQualifier() != EvqConst)
1045 {
1046 return EvqTemporary;
1047 }
1048 return EvqConst;
1049}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001050
1051// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001052void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001053{
Olli Etuaho1dded802016-08-18 18:13:13 +03001054 ASSERT(!isMultiplication() ||
1055 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1056
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001057 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1058 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001059 if (mOp == EOpComma)
1060 {
1061 setType(mRight->getType());
1062 return;
1063 }
1064
Jamie Madillb1a85f42014-08-19 15:23:24 -04001065 // Base assumption: just make the type the same as the left
1066 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001067 setType(mLeft->getType());
1068
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001069 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001070 // Binary operations results in temporary variables unless both
1071 // operands are const.
1072 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1073 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001074 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001075 getTypePointer()->setQualifier(EvqTemporary);
1076 }
1077
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001078 // Handle indexing ops.
1079 switch (mOp)
1080 {
1081 case EOpIndexDirect:
1082 case EOpIndexIndirect:
1083 if (mLeft->isArray())
1084 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001085 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001086 }
1087 else if (mLeft->isMatrix())
1088 {
1089 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1090 static_cast<unsigned char>(mLeft->getRows())));
1091 }
1092 else if (mLeft->isVector())
1093 {
1094 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1095 }
1096 else
1097 {
1098 UNREACHABLE();
1099 }
1100 return;
1101 case EOpIndexDirectStruct:
1102 {
1103 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1104 const int i = mRight->getAsConstantUnion()->getIConst(0);
1105 setType(*fields[i]->type());
1106 getTypePointer()->setQualifier(resultQualifier);
1107 return;
1108 }
1109 case EOpIndexDirectInterfaceBlock:
1110 {
1111 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1112 const int i = mRight->getAsConstantUnion()->getIConst(0);
1113 setType(*fields[i]->type());
1114 getTypePointer()->setQualifier(resultQualifier);
1115 return;
1116 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001117 default:
1118 break;
1119 }
1120
1121 ASSERT(mLeft->isArray() == mRight->isArray());
1122
1123 // The result gets promoted to the highest precision.
1124 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1125 getTypePointer()->setPrecision(higherPrecision);
1126
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001127 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001128
1129 //
1130 // All scalars or structs. Code after this test assumes this case is removed!
1131 //
1132 if (nominalSize == 1)
1133 {
1134 switch (mOp)
1135 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001136 //
1137 // Promote to conditional
1138 //
1139 case EOpEqual:
1140 case EOpNotEqual:
1141 case EOpLessThan:
1142 case EOpGreaterThan:
1143 case EOpLessThanEqual:
1144 case EOpGreaterThanEqual:
1145 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1146 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001147
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001148 //
1149 // And and Or operate on conditionals
1150 //
1151 case EOpLogicalAnd:
1152 case EOpLogicalXor:
1153 case EOpLogicalOr:
1154 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1155 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1156 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001157
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001158 default:
1159 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001160 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001161 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001162 }
1163
1164 // If we reach here, at least one of the operands is vector or matrix.
1165 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001166 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001167
Jamie Madillb1a85f42014-08-19 15:23:24 -04001168 switch (mOp)
1169 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001170 case EOpMul:
1171 break;
1172 case EOpMatrixTimesScalar:
1173 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001174 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001175 setType(TType(basicType, higherPrecision, resultQualifier,
1176 static_cast<unsigned char>(mRight->getCols()),
1177 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001178 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001179 break;
1180 case EOpMatrixTimesVector:
1181 setType(TType(basicType, higherPrecision, resultQualifier,
1182 static_cast<unsigned char>(mLeft->getRows()), 1));
1183 break;
1184 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001185 setType(TType(basicType, higherPrecision, resultQualifier,
1186 static_cast<unsigned char>(mRight->getCols()),
1187 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001188 break;
1189 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001190 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001191 static_cast<unsigned char>(nominalSize), 1));
1192 break;
1193 case EOpVectorTimesMatrix:
1194 setType(TType(basicType, higherPrecision, resultQualifier,
1195 static_cast<unsigned char>(mRight->getCols()), 1));
1196 break;
1197 case EOpMulAssign:
1198 case EOpVectorTimesScalarAssign:
1199 case EOpVectorTimesMatrixAssign:
1200 case EOpMatrixTimesScalarAssign:
1201 case EOpMatrixTimesMatrixAssign:
1202 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1203 break;
1204 case EOpAssign:
1205 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001206 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1207 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1208 break;
1209 case EOpAdd:
1210 case EOpSub:
1211 case EOpDiv:
1212 case EOpIMod:
1213 case EOpBitShiftLeft:
1214 case EOpBitShiftRight:
1215 case EOpBitwiseAnd:
1216 case EOpBitwiseXor:
1217 case EOpBitwiseOr:
1218 case EOpAddAssign:
1219 case EOpSubAssign:
1220 case EOpDivAssign:
1221 case EOpIModAssign:
1222 case EOpBitShiftLeftAssign:
1223 case EOpBitShiftRightAssign:
1224 case EOpBitwiseAndAssign:
1225 case EOpBitwiseXorAssign:
1226 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001227 {
1228 const int secondarySize =
1229 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1230 setType(TType(basicType, higherPrecision, resultQualifier,
1231 static_cast<unsigned char>(nominalSize),
1232 static_cast<unsigned char>(secondarySize)));
1233 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001234 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001235 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001236 case EOpEqual:
1237 case EOpNotEqual:
1238 case EOpLessThan:
1239 case EOpGreaterThan:
1240 case EOpLessThanEqual:
1241 case EOpGreaterThanEqual:
1242 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1243 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001244 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001245 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001246
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001247 case EOpIndexDirect:
1248 case EOpIndexIndirect:
1249 case EOpIndexDirectInterfaceBlock:
1250 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001251 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001252 UNREACHABLE();
1253 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001254 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001255 UNREACHABLE();
1256 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001257 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001258}
1259
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001260const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001261{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001262 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001263 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001264 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001265 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001266 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001267 size_t arrayElementSize = arrayElementType.getObjectSize();
1268 return &mUnionArrayPointer[arrayElementSize * index];
1269 }
1270 else if (isMatrix())
1271 {
1272 ASSERT(index < getType().getCols());
1273 int size = getType().getRows();
1274 return &mUnionArrayPointer[size * index];
1275 }
1276 else if (isVector())
1277 {
1278 ASSERT(index < getType().getNominalSize());
1279 return &mUnionArrayPointer[index];
1280 }
1281 else
1282 {
1283 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001284 return nullptr;
1285 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001286}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001287
Olli Etuahob6fa0432016-09-28 16:28:05 +01001288TIntermTyped *TIntermSwizzle::fold()
1289{
1290 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1291 if (operandConstant == nullptr)
1292 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001293 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001294 }
1295
1296 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1297 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1298 {
1299 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1300 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001301 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001302}
1303
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001304TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1305{
1306 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1307 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1308 switch (mOp)
1309 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001310 case EOpComma:
1311 {
1312 if (mLeft->hasSideEffects())
1313 {
1314 return this;
1315 }
1316 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1317 return mRight;
1318 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001319 case EOpIndexDirect:
1320 {
1321 if (leftConstant == nullptr || rightConstant == nullptr)
1322 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001323 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001324 }
1325 int index = rightConstant->getIConst(0);
1326
1327 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001328 if (!constArray)
1329 {
1330 return this;
1331 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001332 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001333 }
1334 case EOpIndexDirectStruct:
1335 {
1336 if (leftConstant == nullptr || rightConstant == nullptr)
1337 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001338 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001339 }
1340 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1341 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1342
1343 size_t previousFieldsSize = 0;
1344 for (size_t i = 0; i < index; ++i)
1345 {
1346 previousFieldsSize += fields[i]->type()->getObjectSize();
1347 }
1348
1349 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
Olli Etuaho2768bc82017-12-12 11:51:48 +02001350 return CreateFoldedNode(constArray + previousFieldsSize, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001351 }
1352 case EOpIndexIndirect:
1353 case EOpIndexDirectInterfaceBlock:
1354 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001355 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001356 default:
1357 {
1358 if (leftConstant == nullptr || rightConstant == nullptr)
1359 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001360 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001361 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001362 TConstantUnion *constArray =
1363 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001364 if (!constArray)
1365 {
1366 return this;
1367 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001368 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001369 }
1370 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001371}
1372
Olli Etuahof119a262016-08-19 15:54:22 +03001373TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001374{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301375 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001376
1377 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301378 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001379 // The size of runtime-sized arrays may only be determined at runtime.
1380 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001381 {
1382 return this;
1383 }
1384 constArray = new TConstantUnion[1];
1385 constArray->setIConst(mOperand->getOutermostArraySize());
1386 }
1387 else
1388 {
1389 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1390 if (operandConstant == nullptr)
1391 {
1392 return this;
1393 }
1394
1395 switch (mOp)
1396 {
1397 case EOpAny:
1398 case EOpAll:
1399 case EOpLength:
1400 case EOpTranspose:
1401 case EOpDeterminant:
1402 case EOpInverse:
1403 case EOpPackSnorm2x16:
1404 case EOpUnpackSnorm2x16:
1405 case EOpPackUnorm2x16:
1406 case EOpUnpackUnorm2x16:
1407 case EOpPackHalf2x16:
1408 case EOpUnpackHalf2x16:
1409 case EOpPackUnorm4x8:
1410 case EOpPackSnorm4x8:
1411 case EOpUnpackUnorm4x8:
1412 case EOpUnpackSnorm4x8:
1413 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1414 break;
1415 default:
1416 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1417 break;
1418 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301419 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001420 if (constArray == nullptr)
1421 {
1422 return this;
1423 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001424 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001425}
1426
Olli Etuahof119a262016-08-19 15:54:22 +03001427TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001428{
1429 // Make sure that all params are constant before actual constant folding.
1430 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001431 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001432 if (param->getAsConstantUnion() == nullptr)
1433 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001434 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001435 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001436 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001437 TConstantUnion *constArray = nullptr;
1438 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001439 {
Olli Etuahof119a262016-08-19 15:54:22 +03001440 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001441 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001442 else
Olli Etuaho2768bc82017-12-12 11:51:48 +02001443 {
1444 ASSERT(CanFoldAggregateBuiltInOp(mOp));
Olli Etuahof119a262016-08-19 15:54:22 +03001445 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001446 }
1447 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001448}
1449
Jamie Madillb1a85f42014-08-19 15:23:24 -04001450//
1451// The fold functions see if an operation on a constant can be done in place,
1452// without generating run-time code.
1453//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001454// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001455//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001456TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1457 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001458 TDiagnostics *diagnostics,
1459 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001460{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001461 const TConstantUnion *leftArray = getUnionArrayPointer();
1462 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001463
Olli Etuahof119a262016-08-19 15:54:22 +03001464 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001465
1466 size_t objectSize = getType().getObjectSize();
1467
1468 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1469 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1470 {
1471 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1472 }
1473 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1474 {
1475 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001476 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001477 objectSize = rightNode->getType().getObjectSize();
1478 }
1479
1480 TConstantUnion *resultArray = nullptr;
1481
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001482 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001483 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001484 case EOpAdd:
1485 resultArray = new TConstantUnion[objectSize];
1486 for (size_t i = 0; i < objectSize; i++)
1487 resultArray[i] =
1488 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1489 break;
1490 case EOpSub:
1491 resultArray = new TConstantUnion[objectSize];
1492 for (size_t i = 0; i < objectSize; i++)
1493 resultArray[i] =
1494 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1495 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001496
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001497 case EOpMul:
1498 case EOpVectorTimesScalar:
1499 case EOpMatrixTimesScalar:
1500 resultArray = new TConstantUnion[objectSize];
1501 for (size_t i = 0; i < objectSize; i++)
1502 resultArray[i] =
1503 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1504 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001505
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001506 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001507 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001508 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001509 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001510
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001511 const int leftCols = getCols();
1512 const int leftRows = getRows();
1513 const int rightCols = rightNode->getType().getCols();
1514 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001515 const int resultCols = rightCols;
1516 const int resultRows = leftRows;
1517
1518 resultArray = new TConstantUnion[resultCols * resultRows];
1519 for (int row = 0; row < resultRows; row++)
1520 {
1521 for (int column = 0; column < resultCols; column++)
1522 {
1523 resultArray[resultRows * column + row].setFConst(0.0f);
1524 for (int i = 0; i < leftCols; i++)
1525 {
1526 resultArray[resultRows * column + row].setFConst(
1527 resultArray[resultRows * column + row].getFConst() +
1528 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001529 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001530 }
1531 }
1532 }
1533 }
1534 break;
1535
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001536 case EOpDiv:
1537 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001538 {
1539 resultArray = new TConstantUnion[objectSize];
1540 for (size_t i = 0; i < objectSize; i++)
1541 {
1542 switch (getType().getBasicType())
1543 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001544 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001545 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001546 ASSERT(op == EOpDiv);
1547 float dividend = leftArray[i].getFConst();
1548 float divisor = rightArray[i].getFConst();
1549 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001550 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001551 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001552 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001553 diagnostics->warning(
1554 getLine(),
1555 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001556 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001557 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001558 }
1559 else
1560 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001561 diagnostics->warning(getLine(),
1562 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001563 bool negativeResult =
1564 std::signbit(dividend) != std::signbit(divisor);
1565 resultArray[i].setFConst(
1566 negativeResult ? -std::numeric_limits<float>::infinity()
1567 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001568 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001569 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001570 else if (gl::isInf(dividend) && gl::isInf(divisor))
1571 {
1572 diagnostics->warning(getLine(),
1573 "Infinity divided by infinity during constant "
1574 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001575 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001576 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1577 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001578 else
1579 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001580 float result = dividend / divisor;
1581 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001582 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001583 diagnostics->warning(
1584 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001585 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001586 }
1587 resultArray[i].setFConst(result);
1588 }
1589 break;
1590 }
1591 case EbtInt:
1592 if (rightArray[i] == 0)
1593 {
1594 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001595 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001596 resultArray[i].setIConst(INT_MAX);
1597 }
1598 else
1599 {
1600 int lhs = leftArray[i].getIConst();
1601 int divisor = rightArray[i].getIConst();
1602 if (op == EOpDiv)
1603 {
1604 // Check for the special case where the minimum representable number
1605 // is
1606 // divided by -1. If left alone this leads to integer overflow in
1607 // C++.
1608 // ESSL 3.00.6 section 4.1.3 Integers:
1609 // "However, for the case where the minimum representable value is
1610 // divided by -1, it is allowed to return either the minimum
1611 // representable value or the maximum representable value."
1612 if (lhs == -0x7fffffff - 1 && divisor == -1)
1613 {
1614 resultArray[i].setIConst(0x7fffffff);
1615 }
1616 else
1617 {
1618 resultArray[i].setIConst(lhs / divisor);
1619 }
Olli Etuahod4453572016-09-27 13:21:46 +01001620 }
1621 else
1622 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001623 ASSERT(op == EOpIMod);
1624 if (lhs < 0 || divisor < 0)
1625 {
1626 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1627 // when
1628 // either one of the operands is negative.
1629 diagnostics->warning(getLine(),
1630 "Negative modulus operator operand "
1631 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001632 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001633 resultArray[i].setIConst(0);
1634 }
1635 else
1636 {
1637 resultArray[i].setIConst(lhs % divisor);
1638 }
Olli Etuahod4453572016-09-27 13:21:46 +01001639 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001640 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001641 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001642
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001643 case EbtUInt:
1644 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001645 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001646 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001647 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001648 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001649 }
1650 else
1651 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001652 if (op == EOpDiv)
1653 {
1654 resultArray[i].setUConst(leftArray[i].getUConst() /
1655 rightArray[i].getUConst());
1656 }
1657 else
1658 {
1659 ASSERT(op == EOpIMod);
1660 resultArray[i].setUConst(leftArray[i].getUConst() %
1661 rightArray[i].getUConst());
1662 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001663 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001664 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001665
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001666 default:
1667 UNREACHABLE();
1668 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001669 }
1670 }
1671 }
1672 break;
1673
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001674 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001675 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001676 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001677 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001678
1679 const int matrixCols = getCols();
1680 const int matrixRows = getRows();
1681
1682 resultArray = new TConstantUnion[matrixRows];
1683
1684 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1685 {
1686 resultArray[matrixRow].setFConst(0.0f);
1687 for (int col = 0; col < matrixCols; col++)
1688 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001689 resultArray[matrixRow].setFConst(
1690 resultArray[matrixRow].getFConst() +
1691 leftArray[col * matrixRows + matrixRow].getFConst() *
1692 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001693 }
1694 }
1695 }
1696 break;
1697
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001698 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001699 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001700 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001701 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001702
1703 const int matrixCols = rightNode->getType().getCols();
1704 const int matrixRows = rightNode->getType().getRows();
1705
1706 resultArray = new TConstantUnion[matrixCols];
1707
1708 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1709 {
1710 resultArray[matrixCol].setFConst(0.0f);
1711 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1712 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001713 resultArray[matrixCol].setFConst(
1714 resultArray[matrixCol].getFConst() +
1715 leftArray[matrixRow].getFConst() *
1716 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001717 }
1718 }
1719 }
1720 break;
1721
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001722 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001723 {
1724 resultArray = new TConstantUnion[objectSize];
1725 for (size_t i = 0; i < objectSize; i++)
1726 {
1727 resultArray[i] = leftArray[i] && rightArray[i];
1728 }
1729 }
1730 break;
1731
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001732 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001733 {
1734 resultArray = new TConstantUnion[objectSize];
1735 for (size_t i = 0; i < objectSize; i++)
1736 {
1737 resultArray[i] = leftArray[i] || rightArray[i];
1738 }
1739 }
1740 break;
1741
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001742 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001743 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001744 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001745 resultArray = new TConstantUnion[objectSize];
1746 for (size_t i = 0; i < objectSize; i++)
1747 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001748 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001749 }
1750 }
1751 break;
1752
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001753 case EOpBitwiseAnd:
1754 resultArray = new TConstantUnion[objectSize];
1755 for (size_t i = 0; i < objectSize; i++)
1756 resultArray[i] = leftArray[i] & rightArray[i];
1757 break;
1758 case EOpBitwiseXor:
1759 resultArray = new TConstantUnion[objectSize];
1760 for (size_t i = 0; i < objectSize; i++)
1761 resultArray[i] = leftArray[i] ^ rightArray[i];
1762 break;
1763 case EOpBitwiseOr:
1764 resultArray = new TConstantUnion[objectSize];
1765 for (size_t i = 0; i < objectSize; i++)
1766 resultArray[i] = leftArray[i] | rightArray[i];
1767 break;
1768 case EOpBitShiftLeft:
1769 resultArray = new TConstantUnion[objectSize];
1770 for (size_t i = 0; i < objectSize; i++)
1771 resultArray[i] =
1772 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1773 break;
1774 case EOpBitShiftRight:
1775 resultArray = new TConstantUnion[objectSize];
1776 for (size_t i = 0; i < objectSize; i++)
1777 resultArray[i] =
1778 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1779 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001780
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001781 case EOpLessThan:
1782 ASSERT(objectSize == 1);
1783 resultArray = new TConstantUnion[1];
1784 resultArray->setBConst(*leftArray < *rightArray);
1785 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001786
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001787 case EOpGreaterThan:
1788 ASSERT(objectSize == 1);
1789 resultArray = new TConstantUnion[1];
1790 resultArray->setBConst(*leftArray > *rightArray);
1791 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001792
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001793 case EOpLessThanEqual:
1794 ASSERT(objectSize == 1);
1795 resultArray = new TConstantUnion[1];
1796 resultArray->setBConst(!(*leftArray > *rightArray));
1797 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001798
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001799 case EOpGreaterThanEqual:
1800 ASSERT(objectSize == 1);
1801 resultArray = new TConstantUnion[1];
1802 resultArray->setBConst(!(*leftArray < *rightArray));
1803 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001804
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001805 case EOpEqual:
1806 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001807 {
1808 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001809 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001810 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001811 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001812 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001813 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001814 equal = false;
1815 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001816 }
1817 }
1818 if (op == EOpEqual)
1819 {
1820 resultArray->setBConst(equal);
1821 }
1822 else
1823 {
1824 resultArray->setBConst(!equal);
1825 }
1826 }
1827 break;
1828
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001829 default:
1830 UNREACHABLE();
1831 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001832 }
1833 return resultArray;
1834}
1835
Olli Etuahof119a262016-08-19 15:54:22 +03001836// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1837// code. Returns the constant value to keep using. Nullptr should not be returned.
1838TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001839{
Olli Etuahof119a262016-08-19 15:54:22 +03001840 // Do operations where the return type may have a different number of components compared to the
1841 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001842
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001843 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001844 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301845
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001846 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301847 TConstantUnion *resultArray = nullptr;
1848 switch (op)
1849 {
Olli Etuahof119a262016-08-19 15:54:22 +03001850 case EOpAny:
1851 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301852 resultArray = new TConstantUnion();
1853 resultArray->setBConst(false);
1854 for (size_t i = 0; i < objectSize; i++)
1855 {
1856 if (operandArray[i].getBConst())
1857 {
1858 resultArray->setBConst(true);
1859 break;
1860 }
1861 }
1862 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301863
Olli Etuahof119a262016-08-19 15:54:22 +03001864 case EOpAll:
1865 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301866 resultArray = new TConstantUnion();
1867 resultArray->setBConst(true);
1868 for (size_t i = 0; i < objectSize; i++)
1869 {
1870 if (!operandArray[i].getBConst())
1871 {
1872 resultArray->setBConst(false);
1873 break;
1874 }
1875 }
1876 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301877
Olli Etuahof119a262016-08-19 15:54:22 +03001878 case EOpLength:
1879 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301880 resultArray = new TConstantUnion();
1881 resultArray->setFConst(VectorLength(operandArray, objectSize));
1882 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301883
Olli Etuahof119a262016-08-19 15:54:22 +03001884 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301885 {
Olli Etuahof119a262016-08-19 15:54:22 +03001886 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301887 resultArray = new TConstantUnion[objectSize];
1888 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001889 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301890 SetUnionArrayFromMatrix(result, resultArray);
1891 break;
1892 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301893
Olli Etuahof119a262016-08-19 15:54:22 +03001894 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301895 {
Olli Etuahof119a262016-08-19 15:54:22 +03001896 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301897 unsigned int size = getType().getNominalSize();
1898 ASSERT(size >= 2 && size <= 4);
1899 resultArray = new TConstantUnion();
1900 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1901 break;
1902 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301903
Olli Etuahof119a262016-08-19 15:54:22 +03001904 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301905 {
Olli Etuahof119a262016-08-19 15:54:22 +03001906 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301907 unsigned int size = getType().getNominalSize();
1908 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001909 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301910 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1911 SetUnionArrayFromMatrix(result, resultArray);
1912 break;
1913 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301914
Olli Etuahof119a262016-08-19 15:54:22 +03001915 case EOpPackSnorm2x16:
1916 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301917 ASSERT(getType().getNominalSize() == 2);
1918 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001919 resultArray->setUConst(
1920 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301921 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301922
Olli Etuahof119a262016-08-19 15:54:22 +03001923 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301924 {
Olli Etuahof119a262016-08-19 15:54:22 +03001925 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301926 resultArray = new TConstantUnion[2];
1927 float f1, f2;
1928 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1929 resultArray[0].setFConst(f1);
1930 resultArray[1].setFConst(f2);
1931 break;
1932 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301933
Olli Etuahof119a262016-08-19 15:54:22 +03001934 case EOpPackUnorm2x16:
1935 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301936 ASSERT(getType().getNominalSize() == 2);
1937 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001938 resultArray->setUConst(
1939 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301940 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301941
Olli Etuahof119a262016-08-19 15:54:22 +03001942 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301943 {
Olli Etuahof119a262016-08-19 15:54:22 +03001944 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945 resultArray = new TConstantUnion[2];
1946 float f1, f2;
1947 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1948 resultArray[0].setFConst(f1);
1949 resultArray[1].setFConst(f2);
1950 break;
1951 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301952
Olli Etuahof119a262016-08-19 15:54:22 +03001953 case EOpPackHalf2x16:
1954 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301955 ASSERT(getType().getNominalSize() == 2);
1956 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001957 resultArray->setUConst(
1958 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301959 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301960
Olli Etuahof119a262016-08-19 15:54:22 +03001961 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301962 {
Olli Etuahof119a262016-08-19 15:54:22 +03001963 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301964 resultArray = new TConstantUnion[2];
1965 float f1, f2;
1966 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1967 resultArray[0].setFConst(f1);
1968 resultArray[1].setFConst(f2);
1969 break;
1970 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301971
Olli Etuaho25aef452017-01-29 16:15:44 -08001972 case EOpPackUnorm4x8:
1973 {
1974 ASSERT(getType().getBasicType() == EbtFloat);
1975 resultArray = new TConstantUnion();
1976 resultArray->setUConst(
1977 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1978 operandArray[2].getFConst(), operandArray[3].getFConst()));
1979 break;
1980 }
1981 case EOpPackSnorm4x8:
1982 {
1983 ASSERT(getType().getBasicType() == EbtFloat);
1984 resultArray = new TConstantUnion();
1985 resultArray->setUConst(
1986 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1987 operandArray[2].getFConst(), operandArray[3].getFConst()));
1988 break;
1989 }
1990 case EOpUnpackUnorm4x8:
1991 {
1992 ASSERT(getType().getBasicType() == EbtUInt);
1993 resultArray = new TConstantUnion[4];
1994 float f[4];
1995 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
1996 for (size_t i = 0; i < 4; ++i)
1997 {
1998 resultArray[i].setFConst(f[i]);
1999 }
2000 break;
2001 }
2002 case EOpUnpackSnorm4x8:
2003 {
2004 ASSERT(getType().getBasicType() == EbtUInt);
2005 resultArray = new TConstantUnion[4];
2006 float f[4];
2007 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2008 for (size_t i = 0; i < 4; ++i)
2009 {
2010 resultArray[i].setFConst(f[i]);
2011 }
2012 break;
2013 }
2014
Olli Etuahof119a262016-08-19 15:54:22 +03002015 default:
2016 UNREACHABLE();
2017 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302018 }
2019
2020 return resultArray;
2021}
2022
Olli Etuahof119a262016-08-19 15:54:22 +03002023TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2024 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302025{
Olli Etuahof119a262016-08-19 15:54:22 +03002026 // Do unary operations where each component of the result is computed based on the corresponding
2027 // component of the operand. Also folds normalize, though the divisor in that case takes all
2028 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302029
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002030 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002031 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002032
2033 size_t objectSize = getType().getObjectSize();
2034
Arun Patoleab2b9a22015-07-06 18:27:56 +05302035 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2036 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302037 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002038 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302039 {
Olli Etuahof119a262016-08-19 15:54:22 +03002040 case EOpNegative:
2041 switch (getType().getBasicType())
2042 {
2043 case EbtFloat:
2044 resultArray[i].setFConst(-operandArray[i].getFConst());
2045 break;
2046 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002047 if (operandArray[i] == std::numeric_limits<int>::min())
2048 {
2049 // The minimum representable integer doesn't have a positive
2050 // counterpart, rather the negation overflows and in ESSL is supposed to
2051 // wrap back to the minimum representable integer. Make sure that we
2052 // don't actually let the negation overflow, which has undefined
2053 // behavior in C++.
2054 resultArray[i].setIConst(std::numeric_limits<int>::min());
2055 }
2056 else
2057 {
2058 resultArray[i].setIConst(-operandArray[i].getIConst());
2059 }
Olli Etuahof119a262016-08-19 15:54:22 +03002060 break;
2061 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002062 if (operandArray[i] == 0x80000000u)
2063 {
2064 resultArray[i].setUConst(0x80000000u);
2065 }
2066 else
2067 {
2068 resultArray[i].setUConst(static_cast<unsigned int>(
2069 -static_cast<int>(operandArray[i].getUConst())));
2070 }
Olli Etuahof119a262016-08-19 15:54:22 +03002071 break;
2072 default:
2073 UNREACHABLE();
2074 return nullptr;
2075 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302076 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302077
Olli Etuahof119a262016-08-19 15:54:22 +03002078 case EOpPositive:
2079 switch (getType().getBasicType())
2080 {
2081 case EbtFloat:
2082 resultArray[i].setFConst(operandArray[i].getFConst());
2083 break;
2084 case EbtInt:
2085 resultArray[i].setIConst(operandArray[i].getIConst());
2086 break;
2087 case EbtUInt:
2088 resultArray[i].setUConst(static_cast<unsigned int>(
2089 static_cast<int>(operandArray[i].getUConst())));
2090 break;
2091 default:
2092 UNREACHABLE();
2093 return nullptr;
2094 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302095 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302096
Olli Etuahof119a262016-08-19 15:54:22 +03002097 case EOpLogicalNot:
2098 switch (getType().getBasicType())
2099 {
2100 case EbtBool:
2101 resultArray[i].setBConst(!operandArray[i].getBConst());
2102 break;
2103 default:
2104 UNREACHABLE();
2105 return nullptr;
2106 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302107 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302108
Olli Etuahof119a262016-08-19 15:54:22 +03002109 case EOpBitwiseNot:
2110 switch (getType().getBasicType())
2111 {
2112 case EbtInt:
2113 resultArray[i].setIConst(~operandArray[i].getIConst());
2114 break;
2115 case EbtUInt:
2116 resultArray[i].setUConst(~operandArray[i].getUConst());
2117 break;
2118 default:
2119 UNREACHABLE();
2120 return nullptr;
2121 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302122 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302123
Olli Etuahof119a262016-08-19 15:54:22 +03002124 case EOpRadians:
2125 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302126 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2127 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302128
Olli Etuahof119a262016-08-19 15:54:22 +03002129 case EOpDegrees:
2130 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302131 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2132 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302133
Olli Etuahof119a262016-08-19 15:54:22 +03002134 case EOpSin:
2135 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302137
Olli Etuahof119a262016-08-19 15:54:22 +03002138 case EOpCos:
2139 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2140 break;
2141
2142 case EOpTan:
2143 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2144 break;
2145
2146 case EOpAsin:
2147 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2148 // 0.
2149 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2150 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2151 diagnostics, &resultArray[i]);
2152 else
2153 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2154 break;
2155
2156 case EOpAcos:
2157 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2158 // 0.
2159 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2160 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2161 diagnostics, &resultArray[i]);
2162 else
2163 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2164 break;
2165
2166 case EOpAtan:
2167 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2168 break;
2169
2170 case EOpSinh:
2171 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2172 break;
2173
2174 case EOpCosh:
2175 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2176 break;
2177
2178 case EOpTanh:
2179 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2180 break;
2181
2182 case EOpAsinh:
2183 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2184 break;
2185
2186 case EOpAcosh:
2187 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2188 if (operandArray[i].getFConst() < 1.0f)
2189 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2190 diagnostics, &resultArray[i]);
2191 else
2192 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2193 break;
2194
2195 case EOpAtanh:
2196 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2197 // 0.
2198 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2199 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2200 diagnostics, &resultArray[i]);
2201 else
2202 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2203 break;
2204
2205 case EOpAbs:
2206 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302207 {
Olli Etuahof119a262016-08-19 15:54:22 +03002208 case EbtFloat:
2209 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2210 break;
2211 case EbtInt:
2212 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2213 break;
2214 default:
2215 UNREACHABLE();
2216 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302217 }
2218 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002219
2220 case EOpSign:
2221 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302222 {
Olli Etuahof119a262016-08-19 15:54:22 +03002223 case EbtFloat:
2224 {
2225 float fConst = operandArray[i].getFConst();
2226 float fResult = 0.0f;
2227 if (fConst > 0.0f)
2228 fResult = 1.0f;
2229 else if (fConst < 0.0f)
2230 fResult = -1.0f;
2231 resultArray[i].setFConst(fResult);
2232 break;
2233 }
2234 case EbtInt:
2235 {
2236 int iConst = operandArray[i].getIConst();
2237 int iResult = 0;
2238 if (iConst > 0)
2239 iResult = 1;
2240 else if (iConst < 0)
2241 iResult = -1;
2242 resultArray[i].setIConst(iResult);
2243 break;
2244 }
2245 default:
2246 UNREACHABLE();
2247 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302248 }
2249 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302250
Olli Etuahof119a262016-08-19 15:54:22 +03002251 case EOpFloor:
2252 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2253 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302254
Olli Etuahof119a262016-08-19 15:54:22 +03002255 case EOpTrunc:
2256 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2257 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302258
Olli Etuahof119a262016-08-19 15:54:22 +03002259 case EOpRound:
2260 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2261 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302262
Olli Etuahof119a262016-08-19 15:54:22 +03002263 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302264 {
Olli Etuahof119a262016-08-19 15:54:22 +03002265 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302266 float x = operandArray[i].getFConst();
2267 float result;
2268 float fractPart = modff(x, &result);
2269 if (fabsf(fractPart) == 0.5f)
2270 result = 2.0f * roundf(x / 2.0f);
2271 else
2272 result = roundf(x);
2273 resultArray[i].setFConst(result);
2274 break;
2275 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302276
Olli Etuahof119a262016-08-19 15:54:22 +03002277 case EOpCeil:
2278 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2279 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302280
Olli Etuahof119a262016-08-19 15:54:22 +03002281 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302282 {
Olli Etuahof119a262016-08-19 15:54:22 +03002283 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302284 float x = operandArray[i].getFConst();
2285 resultArray[i].setFConst(x - floorf(x));
2286 break;
2287 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302288
Olli Etuahof119a262016-08-19 15:54:22 +03002289 case EOpIsNan:
2290 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302291 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2292 break;
Arun Patole551279e2015-07-07 18:18:23 +05302293
Olli Etuahof119a262016-08-19 15:54:22 +03002294 case EOpIsInf:
2295 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302296 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2297 break;
Arun Patole551279e2015-07-07 18:18:23 +05302298
Olli Etuahof119a262016-08-19 15:54:22 +03002299 case EOpFloatBitsToInt:
2300 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302301 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2302 break;
Arun Patole551279e2015-07-07 18:18:23 +05302303
Olli Etuahof119a262016-08-19 15:54:22 +03002304 case EOpFloatBitsToUint:
2305 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302306 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2307 break;
Arun Patole551279e2015-07-07 18:18:23 +05302308
Olli Etuahof119a262016-08-19 15:54:22 +03002309 case EOpIntBitsToFloat:
2310 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302311 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2312 break;
Arun Patole551279e2015-07-07 18:18:23 +05302313
Olli Etuahof119a262016-08-19 15:54:22 +03002314 case EOpUintBitsToFloat:
2315 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302316 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2317 break;
Arun Patole551279e2015-07-07 18:18:23 +05302318
Olli Etuahof119a262016-08-19 15:54:22 +03002319 case EOpExp:
2320 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2321 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302322
Olli Etuahof119a262016-08-19 15:54:22 +03002323 case EOpLog:
2324 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2325 if (operandArray[i].getFConst() <= 0.0f)
2326 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2327 diagnostics, &resultArray[i]);
2328 else
2329 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2330 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302331
Olli Etuahof119a262016-08-19 15:54:22 +03002332 case EOpExp2:
2333 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2334 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302335
Olli Etuahof119a262016-08-19 15:54:22 +03002336 case EOpLog2:
2337 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2338 // And log2f is not available on some plarforms like old android, so just using
2339 // log(x)/log(2) here.
2340 if (operandArray[i].getFConst() <= 0.0f)
2341 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2342 diagnostics, &resultArray[i]);
2343 else
2344 {
2345 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2346 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2347 }
2348 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302349
Olli Etuahof119a262016-08-19 15:54:22 +03002350 case EOpSqrt:
2351 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2352 if (operandArray[i].getFConst() < 0.0f)
2353 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2354 diagnostics, &resultArray[i]);
2355 else
2356 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2357 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302358
Olli Etuahof119a262016-08-19 15:54:22 +03002359 case EOpInverseSqrt:
2360 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2361 // so getting the square root first using builtin function sqrt() and then taking
2362 // its inverse.
2363 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2364 // result to 0.
2365 if (operandArray[i].getFConst() <= 0.0f)
2366 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2367 diagnostics, &resultArray[i]);
2368 else
2369 {
2370 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2371 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2372 }
2373 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302374
Olli Etuahod68924e2017-01-02 17:34:40 +00002375 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002376 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302377 resultArray[i].setBConst(!operandArray[i].getBConst());
2378 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302379
Olli Etuahof119a262016-08-19 15:54:22 +03002380 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302381 {
Olli Etuahof119a262016-08-19 15:54:22 +03002382 ASSERT(getType().getBasicType() == EbtFloat);
2383 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302384 float length = VectorLength(operandArray, objectSize);
2385 if (length)
2386 resultArray[i].setFConst(x / length);
2387 else
Olli Etuahof119a262016-08-19 15:54:22 +03002388 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2389 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302390 break;
2391 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002392 case EOpBitfieldReverse:
2393 {
2394 uint32_t value;
2395 if (getType().getBasicType() == EbtInt)
2396 {
2397 value = static_cast<uint32_t>(operandArray[i].getIConst());
2398 }
2399 else
2400 {
2401 ASSERT(getType().getBasicType() == EbtUInt);
2402 value = operandArray[i].getUConst();
2403 }
2404 uint32_t result = gl::BitfieldReverse(value);
2405 if (getType().getBasicType() == EbtInt)
2406 {
2407 resultArray[i].setIConst(static_cast<int32_t>(result));
2408 }
2409 else
2410 {
2411 resultArray[i].setUConst(result);
2412 }
2413 break;
2414 }
2415 case EOpBitCount:
2416 {
2417 uint32_t value;
2418 if (getType().getBasicType() == EbtInt)
2419 {
2420 value = static_cast<uint32_t>(operandArray[i].getIConst());
2421 }
2422 else
2423 {
2424 ASSERT(getType().getBasicType() == EbtUInt);
2425 value = operandArray[i].getUConst();
2426 }
2427 int result = gl::BitCount(value);
2428 resultArray[i].setIConst(result);
2429 break;
2430 }
2431 case EOpFindLSB:
2432 {
2433 uint32_t value;
2434 if (getType().getBasicType() == EbtInt)
2435 {
2436 value = static_cast<uint32_t>(operandArray[i].getIConst());
2437 }
2438 else
2439 {
2440 ASSERT(getType().getBasicType() == EbtUInt);
2441 value = operandArray[i].getUConst();
2442 }
2443 resultArray[i].setIConst(gl::FindLSB(value));
2444 break;
2445 }
2446 case EOpFindMSB:
2447 {
2448 uint32_t value;
2449 if (getType().getBasicType() == EbtInt)
2450 {
2451 int intValue = operandArray[i].getIConst();
2452 value = static_cast<uint32_t>(intValue);
2453 if (intValue < 0)
2454 {
2455 // Look for zero instead of one in value. This also handles the intValue ==
2456 // -1 special case, where the return value needs to be -1.
2457 value = ~value;
2458 }
2459 }
2460 else
2461 {
2462 ASSERT(getType().getBasicType() == EbtUInt);
2463 value = operandArray[i].getUConst();
2464 }
2465 resultArray[i].setIConst(gl::FindMSB(value));
2466 break;
2467 }
Olli Etuahof119a262016-08-19 15:54:22 +03002468 case EOpDFdx:
2469 case EOpDFdy:
2470 case EOpFwidth:
2471 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302472 // Derivatives of constant arguments should be 0.
2473 resultArray[i].setFConst(0.0f);
2474 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302475
Olli Etuahof119a262016-08-19 15:54:22 +03002476 default:
2477 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302478 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302479 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002480
Arun Patoleab2b9a22015-07-06 18:27:56 +05302481 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002482}
2483
Olli Etuahof119a262016-08-19 15:54:22 +03002484void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2485 FloatTypeUnaryFunc builtinFunc,
2486 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302487{
2488 ASSERT(builtinFunc);
2489
Olli Etuahof119a262016-08-19 15:54:22 +03002490 ASSERT(getType().getBasicType() == EbtFloat);
2491 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302492}
2493
Jamie Madillb1a85f42014-08-19 15:23:24 -04002494// static
Olli Etuahof119a262016-08-19 15:54:22 +03002495TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002496{
2497 ASSERT(aggregate->getSequence()->size() > 0u);
2498 size_t resultSize = aggregate->getType().getObjectSize();
2499 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2500 TBasicType basicType = aggregate->getBasicType();
2501
2502 size_t resultIndex = 0u;
2503
2504 if (aggregate->getSequence()->size() == 1u)
2505 {
2506 TIntermNode *argument = aggregate->getSequence()->front();
2507 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2508 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2509 // Check the special case of constructing a matrix diagonal from a single scalar,
2510 // or a vector from a single scalar.
2511 if (argumentConstant->getType().getObjectSize() == 1u)
2512 {
2513 if (aggregate->isMatrix())
2514 {
2515 int resultCols = aggregate->getType().getCols();
2516 int resultRows = aggregate->getType().getRows();
2517 for (int col = 0; col < resultCols; ++col)
2518 {
2519 for (int row = 0; row < resultRows; ++row)
2520 {
2521 if (col == row)
2522 {
2523 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2524 }
2525 else
2526 {
2527 resultArray[resultIndex].setFConst(0.0f);
2528 }
2529 ++resultIndex;
2530 }
2531 }
2532 }
2533 else
2534 {
2535 while (resultIndex < resultSize)
2536 {
2537 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2538 ++resultIndex;
2539 }
2540 }
2541 ASSERT(resultIndex == resultSize);
2542 return resultArray;
2543 }
2544 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2545 {
2546 // The special case of constructing a matrix from a matrix.
2547 int argumentCols = argumentConstant->getType().getCols();
2548 int argumentRows = argumentConstant->getType().getRows();
2549 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002550 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002551 for (int col = 0; col < resultCols; ++col)
2552 {
2553 for (int row = 0; row < resultRows; ++row)
2554 {
2555 if (col < argumentCols && row < argumentRows)
2556 {
2557 resultArray[resultIndex].cast(basicType,
2558 argumentUnionArray[col * argumentRows + row]);
2559 }
2560 else if (col == row)
2561 {
2562 resultArray[resultIndex].setFConst(1.0f);
2563 }
2564 else
2565 {
2566 resultArray[resultIndex].setFConst(0.0f);
2567 }
2568 ++resultIndex;
2569 }
2570 }
2571 ASSERT(resultIndex == resultSize);
2572 return resultArray;
2573 }
2574 }
2575
2576 for (TIntermNode *&argument : *aggregate->getSequence())
2577 {
2578 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2579 size_t argumentSize = argumentConstant->getType().getObjectSize();
2580 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2581 for (size_t i = 0u; i < argumentSize; ++i)
2582 {
2583 if (resultIndex >= resultSize)
2584 break;
2585 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2586 ++resultIndex;
2587 }
2588 }
2589 ASSERT(resultIndex == resultSize);
2590 return resultArray;
2591}
2592
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002593bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2594{
2595 switch (op)
2596 {
2597 case EOpAtan:
2598 case EOpPow:
2599 case EOpMod:
2600 case EOpMin:
2601 case EOpMax:
2602 case EOpClamp:
2603 case EOpMix:
2604 case EOpStep:
2605 case EOpSmoothStep:
2606 case EOpLdexp:
2607 case EOpMulMatrixComponentWise:
2608 case EOpOuterProduct:
2609 case EOpEqualComponentWise:
2610 case EOpNotEqualComponentWise:
2611 case EOpLessThanComponentWise:
2612 case EOpLessThanEqualComponentWise:
2613 case EOpGreaterThanComponentWise:
2614 case EOpGreaterThanEqualComponentWise:
2615 case EOpDistance:
2616 case EOpDot:
2617 case EOpCross:
2618 case EOpFaceforward:
2619 case EOpReflect:
2620 case EOpRefract:
2621 case EOpBitfieldExtract:
2622 case EOpBitfieldInsert:
2623 return true;
2624 default:
2625 return false;
2626 }
2627}
2628
Olli Etuaho1d122782015-11-06 15:35:17 +02002629// static
Olli Etuahof119a262016-08-19 15:54:22 +03002630TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2631 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302632{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002633 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002634 TIntermSequence *arguments = aggregate->getSequence();
2635 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2636 std::vector<const TConstantUnion *> unionArrays(argsCount);
2637 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002638 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302639 TBasicType basicType = EbtVoid;
2640 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002641 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302642 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002643 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2644 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302645
2646 if (i == 0)
2647 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002648 basicType = argConstant->getType().getBasicType();
2649 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302650 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002651 unionArrays[i] = argConstant->getUnionArrayPointer();
2652 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002653 if (objectSizes[i] > maxObjectSize)
2654 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302655 }
2656
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002657 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302658 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002659 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302660 if (objectSizes[i] != maxObjectSize)
2661 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2662 }
Arun Patole274f0702015-05-05 13:33:30 +05302663
Olli Etuahob43846e2015-06-02 18:18:57 +03002664 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002665
2666 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302667 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002668 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302669 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002670 ASSERT(basicType == EbtFloat);
2671 resultArray = new TConstantUnion[maxObjectSize];
2672 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302673 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002674 float y = unionArrays[0][i].getFConst();
2675 float x = unionArrays[1][i].getFConst();
2676 // Results are undefined if x and y are both 0.
2677 if (x == 0.0f && y == 0.0f)
2678 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2679 else
2680 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302681 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002682 break;
2683 }
Arun Patolebf790422015-05-18 17:53:04 +05302684
Olli Etuaho51182ab2017-01-22 00:12:29 +00002685 case EOpPow:
2686 {
2687 ASSERT(basicType == EbtFloat);
2688 resultArray = new TConstantUnion[maxObjectSize];
2689 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302690 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002691 float x = unionArrays[0][i].getFConst();
2692 float y = unionArrays[1][i].getFConst();
2693 // Results are undefined if x < 0.
2694 // Results are undefined if x = 0 and y <= 0.
2695 if (x < 0.0f)
2696 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2697 else if (x == 0.0f && y <= 0.0f)
2698 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2699 else
2700 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302701 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002702 break;
2703 }
Arun Patolebf790422015-05-18 17:53:04 +05302704
Olli Etuaho51182ab2017-01-22 00:12:29 +00002705 case EOpMod:
2706 {
2707 ASSERT(basicType == EbtFloat);
2708 resultArray = new TConstantUnion[maxObjectSize];
2709 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302710 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002711 float x = unionArrays[0][i].getFConst();
2712 float y = unionArrays[1][i].getFConst();
2713 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302714 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002715 break;
2716 }
Arun Patolebf790422015-05-18 17:53:04 +05302717
Olli Etuaho51182ab2017-01-22 00:12:29 +00002718 case EOpMin:
2719 {
2720 resultArray = new TConstantUnion[maxObjectSize];
2721 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302722 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002723 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302724 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002725 case EbtFloat:
2726 resultArray[i].setFConst(
2727 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2728 break;
2729 case EbtInt:
2730 resultArray[i].setIConst(
2731 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2732 break;
2733 case EbtUInt:
2734 resultArray[i].setUConst(
2735 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2736 break;
2737 default:
2738 UNREACHABLE();
2739 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302740 }
2741 }
2742 break;
Arun Patole274f0702015-05-05 13:33:30 +05302743 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002744
2745 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302746 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002747 resultArray = new TConstantUnion[maxObjectSize];
2748 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302749 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002750 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302751 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002752 case EbtFloat:
2753 resultArray[i].setFConst(
2754 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2755 break;
2756 case EbtInt:
2757 resultArray[i].setIConst(
2758 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2759 break;
2760 case EbtUInt:
2761 resultArray[i].setUConst(
2762 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2763 break;
2764 default:
2765 UNREACHABLE();
2766 break;
Arun Patole274f0702015-05-05 13:33:30 +05302767 }
2768 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002769 break;
Arun Patole274f0702015-05-05 13:33:30 +05302770 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002771
2772 case EOpStep:
2773 {
2774 ASSERT(basicType == EbtFloat);
2775 resultArray = new TConstantUnion[maxObjectSize];
2776 for (size_t i = 0; i < maxObjectSize; i++)
2777 resultArray[i].setFConst(
2778 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2779 break;
2780 }
2781
2782 case EOpLessThanComponentWise:
2783 {
2784 resultArray = new TConstantUnion[maxObjectSize];
2785 for (size_t i = 0; i < maxObjectSize; i++)
2786 {
2787 switch (basicType)
2788 {
2789 case EbtFloat:
2790 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2791 unionArrays[1][i].getFConst());
2792 break;
2793 case EbtInt:
2794 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2795 unionArrays[1][i].getIConst());
2796 break;
2797 case EbtUInt:
2798 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2799 unionArrays[1][i].getUConst());
2800 break;
2801 default:
2802 UNREACHABLE();
2803 break;
2804 }
2805 }
2806 break;
2807 }
2808
2809 case EOpLessThanEqualComponentWise:
2810 {
2811 resultArray = new TConstantUnion[maxObjectSize];
2812 for (size_t i = 0; i < maxObjectSize; i++)
2813 {
2814 switch (basicType)
2815 {
2816 case EbtFloat:
2817 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2818 unionArrays[1][i].getFConst());
2819 break;
2820 case EbtInt:
2821 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2822 unionArrays[1][i].getIConst());
2823 break;
2824 case EbtUInt:
2825 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2826 unionArrays[1][i].getUConst());
2827 break;
2828 default:
2829 UNREACHABLE();
2830 break;
2831 }
2832 }
2833 break;
2834 }
2835
2836 case EOpGreaterThanComponentWise:
2837 {
2838 resultArray = new TConstantUnion[maxObjectSize];
2839 for (size_t i = 0; i < maxObjectSize; i++)
2840 {
2841 switch (basicType)
2842 {
2843 case EbtFloat:
2844 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2845 unionArrays[1][i].getFConst());
2846 break;
2847 case EbtInt:
2848 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2849 unionArrays[1][i].getIConst());
2850 break;
2851 case EbtUInt:
2852 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2853 unionArrays[1][i].getUConst());
2854 break;
2855 default:
2856 UNREACHABLE();
2857 break;
2858 }
2859 }
2860 break;
2861 }
2862 case EOpGreaterThanEqualComponentWise:
2863 {
2864 resultArray = new TConstantUnion[maxObjectSize];
2865 for (size_t i = 0; i < maxObjectSize; i++)
2866 {
2867 switch (basicType)
2868 {
2869 case EbtFloat:
2870 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2871 unionArrays[1][i].getFConst());
2872 break;
2873 case EbtInt:
2874 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2875 unionArrays[1][i].getIConst());
2876 break;
2877 case EbtUInt:
2878 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2879 unionArrays[1][i].getUConst());
2880 break;
2881 default:
2882 UNREACHABLE();
2883 break;
2884 }
2885 }
2886 }
2887 break;
2888
2889 case EOpEqualComponentWise:
2890 {
2891 resultArray = new TConstantUnion[maxObjectSize];
2892 for (size_t i = 0; i < maxObjectSize; i++)
2893 {
2894 switch (basicType)
2895 {
2896 case EbtFloat:
2897 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2898 unionArrays[1][i].getFConst());
2899 break;
2900 case EbtInt:
2901 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2902 unionArrays[1][i].getIConst());
2903 break;
2904 case EbtUInt:
2905 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2906 unionArrays[1][i].getUConst());
2907 break;
2908 case EbtBool:
2909 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2910 unionArrays[1][i].getBConst());
2911 break;
2912 default:
2913 UNREACHABLE();
2914 break;
2915 }
2916 }
2917 break;
2918 }
2919
2920 case EOpNotEqualComponentWise:
2921 {
2922 resultArray = new TConstantUnion[maxObjectSize];
2923 for (size_t i = 0; i < maxObjectSize; i++)
2924 {
2925 switch (basicType)
2926 {
2927 case EbtFloat:
2928 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2929 unionArrays[1][i].getFConst());
2930 break;
2931 case EbtInt:
2932 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2933 unionArrays[1][i].getIConst());
2934 break;
2935 case EbtUInt:
2936 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2937 unionArrays[1][i].getUConst());
2938 break;
2939 case EbtBool:
2940 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2941 unionArrays[1][i].getBConst());
2942 break;
2943 default:
2944 UNREACHABLE();
2945 break;
2946 }
2947 }
2948 break;
2949 }
2950
2951 case EOpDistance:
2952 {
2953 ASSERT(basicType == EbtFloat);
2954 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2955 resultArray = new TConstantUnion();
2956 for (size_t i = 0; i < maxObjectSize; i++)
2957 {
2958 float x = unionArrays[0][i].getFConst();
2959 float y = unionArrays[1][i].getFConst();
2960 distanceArray[i].setFConst(x - y);
2961 }
2962 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2963 break;
2964 }
2965
2966 case EOpDot:
2967 ASSERT(basicType == EbtFloat);
2968 resultArray = new TConstantUnion();
2969 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2970 break;
2971
2972 case EOpCross:
2973 {
2974 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2975 resultArray = new TConstantUnion[maxObjectSize];
2976 float x0 = unionArrays[0][0].getFConst();
2977 float x1 = unionArrays[0][1].getFConst();
2978 float x2 = unionArrays[0][2].getFConst();
2979 float y0 = unionArrays[1][0].getFConst();
2980 float y1 = unionArrays[1][1].getFConst();
2981 float y2 = unionArrays[1][2].getFConst();
2982 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2983 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2984 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2985 break;
2986 }
2987
2988 case EOpReflect:
2989 {
2990 ASSERT(basicType == EbtFloat);
2991 // genType reflect (genType I, genType N) :
2992 // For the incident vector I and surface orientation N, returns the reflection
2993 // direction:
2994 // I - 2 * dot(N, I) * N.
2995 resultArray = new TConstantUnion[maxObjectSize];
2996 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2997 for (size_t i = 0; i < maxObjectSize; i++)
2998 {
2999 float result = unionArrays[0][i].getFConst() -
3000 2.0f * dotProduct * unionArrays[1][i].getFConst();
3001 resultArray[i].setFConst(result);
3002 }
3003 break;
3004 }
3005
3006 case EOpMulMatrixComponentWise:
3007 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003008 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3009 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003010 // Perform component-wise matrix multiplication.
3011 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003012 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003013 angle::Matrix<float> result =
3014 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3015 SetUnionArrayFromMatrix(result, resultArray);
3016 break;
3017 }
3018
3019 case EOpOuterProduct:
3020 {
3021 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003022 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3023 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003024 resultArray = new TConstantUnion[numRows * numCols];
3025 angle::Matrix<float> result =
3026 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3027 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3028 SetUnionArrayFromMatrix(result, resultArray);
3029 break;
3030 }
3031
3032 case EOpClamp:
3033 {
3034 resultArray = new TConstantUnion[maxObjectSize];
3035 for (size_t i = 0; i < maxObjectSize; i++)
3036 {
3037 switch (basicType)
3038 {
3039 case EbtFloat:
3040 {
3041 float x = unionArrays[0][i].getFConst();
3042 float min = unionArrays[1][i].getFConst();
3043 float max = unionArrays[2][i].getFConst();
3044 // Results are undefined if min > max.
3045 if (min > max)
3046 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3047 &resultArray[i]);
3048 else
3049 resultArray[i].setFConst(gl::clamp(x, min, max));
3050 break;
3051 }
3052
3053 case EbtInt:
3054 {
3055 int x = unionArrays[0][i].getIConst();
3056 int min = unionArrays[1][i].getIConst();
3057 int max = unionArrays[2][i].getIConst();
3058 // Results are undefined if min > max.
3059 if (min > max)
3060 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3061 &resultArray[i]);
3062 else
3063 resultArray[i].setIConst(gl::clamp(x, min, max));
3064 break;
3065 }
3066 case EbtUInt:
3067 {
3068 unsigned int x = unionArrays[0][i].getUConst();
3069 unsigned int min = unionArrays[1][i].getUConst();
3070 unsigned int max = unionArrays[2][i].getUConst();
3071 // Results are undefined if min > max.
3072 if (min > max)
3073 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3074 &resultArray[i]);
3075 else
3076 resultArray[i].setUConst(gl::clamp(x, min, max));
3077 break;
3078 }
3079 default:
3080 UNREACHABLE();
3081 break;
3082 }
3083 }
3084 break;
3085 }
3086
3087 case EOpMix:
3088 {
3089 ASSERT(basicType == EbtFloat);
3090 resultArray = new TConstantUnion[maxObjectSize];
3091 for (size_t i = 0; i < maxObjectSize; i++)
3092 {
3093 float x = unionArrays[0][i].getFConst();
3094 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003095 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003096 if (type == EbtFloat)
3097 {
3098 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3099 float a = unionArrays[2][i].getFConst();
3100 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3101 }
3102 else // 3rd parameter is EbtBool
3103 {
3104 ASSERT(type == EbtBool);
3105 // Selects which vector each returned component comes from.
3106 // For a component of a that is false, the corresponding component of x is
3107 // returned.
3108 // For a component of a that is true, the corresponding component of y is
3109 // returned.
3110 bool a = unionArrays[2][i].getBConst();
3111 resultArray[i].setFConst(a ? y : x);
3112 }
3113 }
3114 break;
3115 }
3116
3117 case EOpSmoothStep:
3118 {
3119 ASSERT(basicType == EbtFloat);
3120 resultArray = new TConstantUnion[maxObjectSize];
3121 for (size_t i = 0; i < maxObjectSize; i++)
3122 {
3123 float edge0 = unionArrays[0][i].getFConst();
3124 float edge1 = unionArrays[1][i].getFConst();
3125 float x = unionArrays[2][i].getFConst();
3126 // Results are undefined if edge0 >= edge1.
3127 if (edge0 >= edge1)
3128 {
3129 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3130 }
3131 else
3132 {
3133 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3134 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3135 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3136 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3137 }
3138 }
3139 break;
3140 }
3141
Olli Etuaho74da73f2017-02-01 15:37:48 +00003142 case EOpLdexp:
3143 {
3144 resultArray = new TConstantUnion[maxObjectSize];
3145 for (size_t i = 0; i < maxObjectSize; i++)
3146 {
3147 float x = unionArrays[0][i].getFConst();
3148 int exp = unionArrays[1][i].getIConst();
3149 if (exp > 128)
3150 {
3151 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3152 }
3153 else
3154 {
3155 resultArray[i].setFConst(gl::Ldexp(x, exp));
3156 }
3157 }
3158 break;
3159 }
3160
Jamie Madille72595b2017-06-06 15:12:26 -04003161 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003162 {
3163 ASSERT(basicType == EbtFloat);
3164 // genType faceforward(genType N, genType I, genType Nref) :
3165 // If dot(Nref, I) < 0 return N, otherwise return -N.
3166 resultArray = new TConstantUnion[maxObjectSize];
3167 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3168 for (size_t i = 0; i < maxObjectSize; i++)
3169 {
3170 if (dotProduct < 0)
3171 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3172 else
3173 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3174 }
3175 break;
3176 }
3177
3178 case EOpRefract:
3179 {
3180 ASSERT(basicType == EbtFloat);
3181 // genType refract(genType I, genType N, float eta) :
3182 // For the incident vector I and surface normal N, and the ratio of indices of
3183 // refraction eta,
3184 // return the refraction vector. The result is computed by
3185 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3186 // if (k < 0.0)
3187 // return genType(0.0)
3188 // else
3189 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3190 resultArray = new TConstantUnion[maxObjectSize];
3191 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3192 for (size_t i = 0; i < maxObjectSize; i++)
3193 {
3194 float eta = unionArrays[2][i].getFConst();
3195 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3196 if (k < 0.0f)
3197 resultArray[i].setFConst(0.0f);
3198 else
3199 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3200 (eta * dotProduct + sqrtf(k)) *
3201 unionArrays[1][i].getFConst());
3202 }
3203 break;
3204 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003205 case EOpBitfieldExtract:
3206 {
3207 resultArray = new TConstantUnion[maxObjectSize];
3208 for (size_t i = 0; i < maxObjectSize; ++i)
3209 {
3210 int offset = unionArrays[1][0].getIConst();
3211 int bits = unionArrays[2][0].getIConst();
3212 if (bits == 0)
3213 {
3214 if (aggregate->getBasicType() == EbtInt)
3215 {
3216 resultArray[i].setIConst(0);
3217 }
3218 else
3219 {
3220 ASSERT(aggregate->getBasicType() == EbtUInt);
3221 resultArray[i].setUConst(0);
3222 }
3223 }
3224 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3225 {
3226 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3227 &resultArray[i]);
3228 }
3229 else
3230 {
3231 // bits can be 32 here, so we need to avoid bit shift overflow.
3232 uint32_t maskMsb = 1u << (bits - 1);
3233 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3234 if (aggregate->getBasicType() == EbtInt)
3235 {
3236 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3237 uint32_t resultUnsigned = (value & mask) >> offset;
3238 if ((resultUnsigned & maskMsb) != 0)
3239 {
3240 // The most significant bits (from bits+1 to the most significant bit)
3241 // should be set to 1.
3242 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3243 resultUnsigned |= higherBitsMask;
3244 }
3245 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3246 }
3247 else
3248 {
3249 ASSERT(aggregate->getBasicType() == EbtUInt);
3250 uint32_t value = unionArrays[0][i].getUConst();
3251 resultArray[i].setUConst((value & mask) >> offset);
3252 }
3253 }
3254 }
3255 break;
3256 }
3257 case EOpBitfieldInsert:
3258 {
3259 resultArray = new TConstantUnion[maxObjectSize];
3260 for (size_t i = 0; i < maxObjectSize; ++i)
3261 {
3262 int offset = unionArrays[2][0].getIConst();
3263 int bits = unionArrays[3][0].getIConst();
3264 if (bits == 0)
3265 {
3266 if (aggregate->getBasicType() == EbtInt)
3267 {
3268 int32_t base = unionArrays[0][i].getIConst();
3269 resultArray[i].setIConst(base);
3270 }
3271 else
3272 {
3273 ASSERT(aggregate->getBasicType() == EbtUInt);
3274 uint32_t base = unionArrays[0][i].getUConst();
3275 resultArray[i].setUConst(base);
3276 }
3277 }
3278 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3279 {
3280 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3281 &resultArray[i]);
3282 }
3283 else
3284 {
3285 // bits can be 32 here, so we need to avoid bit shift overflow.
3286 uint32_t maskMsb = 1u << (bits - 1);
3287 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3288 uint32_t baseMask = ~insertMask;
3289 if (aggregate->getBasicType() == EbtInt)
3290 {
3291 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3292 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3293 uint32_t resultUnsigned =
3294 (base & baseMask) | ((insert << offset) & insertMask);
3295 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3296 }
3297 else
3298 {
3299 ASSERT(aggregate->getBasicType() == EbtUInt);
3300 uint32_t base = unionArrays[0][i].getUConst();
3301 uint32_t insert = unionArrays[1][i].getUConst();
3302 resultArray[i].setUConst((base & baseMask) |
3303 ((insert << offset) & insertMask));
3304 }
3305 }
3306 }
3307 break;
3308 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003309
3310 default:
3311 UNREACHABLE();
3312 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303313 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003314 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303315}
3316
Jamie Madill45bcc782016-11-07 13:58:48 -05003317} // namespace sh