blob: 1f5dfa8549d754aa4b0c4bf5151d25428d8fb7a8 [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
Jamie Madillb1a85f42014-08-19 15:23:24 -0400143////////////////////////////////////////////////////////////////
144//
145// Member functions of the nodes used for building the tree.
146//
147////////////////////////////////////////////////////////////////
148
Olli Etuahod2a67b92014-10-21 16:42:57 +0300149void TIntermTyped::setTypePreservePrecision(const TType &t)
150{
151 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500152 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300153 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
154 mType.setPrecision(precision);
155}
156
Jamie Madillb1a85f42014-08-19 15:23:24 -0400157#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500158 if (node == original) \
159 { \
160 node = static_cast<type *>(replacement); \
161 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400162 }
163
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500164bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400165{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300166 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400167 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
168 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
169 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100170 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400171 return false;
172}
173
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500174bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400175{
176 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
177 return false;
178}
179
Olli Etuahob6fa0432016-09-28 16:28:05 +0100180bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
181{
182 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
183 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
184 return false;
185}
186
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500187bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400188{
189 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
190 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
191 return false;
192}
193
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500194bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400195{
Olli Etuahoa2234302016-08-31 12:05:39 +0300196 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400197 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
198 return false;
199}
200
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000201bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
202{
203 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
204 return false;
205}
206
Olli Etuaho336b1472016-10-05 16:37:55 +0100207bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
208{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000209 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100210 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
211 return false;
212}
213
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500214bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400215{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100216 return replaceChildNodeInternal(original, replacement);
217}
218
219bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
220{
221 return replaceChildNodeInternal(original, replacement);
222}
223
Olli Etuaho16c745a2017-01-16 17:02:27 +0000224bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
225{
226 return replaceChildNodeInternal(original, replacement);
227}
228
Olli Etuaho13389b62016-10-16 11:48:18 +0100229bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
230{
231 return replaceChildNodeInternal(original, replacement);
232}
233
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100234bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
235{
236 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400237 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100238 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400239 }
240 return false;
241}
242
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100243bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
244 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300245{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100246 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300247 {
248 if (*it == original)
249 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100250 it = getSequence()->erase(it);
251 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300252 return true;
253 }
254 }
255 return false;
256}
257
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100258bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
259 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300260{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100261 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300262 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300263 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300264 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100265 auto it = getSequence()->begin() + position;
266 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300267 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300268}
269
Olli Etuaho195be942017-12-04 23:40:14 +0200270TIntermSymbol::TIntermSymbol(const TVariable *variable)
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200271 : TIntermTyped(variable->getType()), mVariable(variable)
Olli Etuaho195be942017-12-04 23:40:14 +0200272{
Olli Etuaho195be942017-12-04 23:40:14 +0200273}
274
Olli Etuahob6af22b2017-12-15 14:05:44 +0200275const TSymbolUniqueId &TIntermSymbol::uniqueId() const
276{
277 return mVariable->uniqueId();
278}
279
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200280const TString &TIntermSymbol::getName() const
281{
282 return mVariable->name();
283}
284
Olli Etuahofe486322017-03-21 09:30:54 +0000285TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
286 TIntermSequence *arguments)
287{
Olli Etuaho0c371002017-12-13 17:00:25 +0400288 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000289}
290
Olli Etuaho0c371002017-12-13 17:00:25 +0400291TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
292 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000293{
Olli Etuaho0c371002017-12-13 17:00:25 +0400294 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000295}
296
297TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
298 TIntermSequence *arguments)
299{
300 TIntermAggregate *callNode =
Olli Etuaho0c371002017-12-13 17:00:25 +0400301 new TIntermAggregate(&func, func.getReturnType(), EOpCallBuiltInFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000302 // Note that name needs to be set before texture function type is determined.
303 callNode->setBuiltInFunctionPrecision();
304 return callNode;
305}
306
307TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000308 TIntermSequence *arguments)
309{
Olli Etuaho0c371002017-12-13 17:00:25 +0400310 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000311}
312
313TIntermAggregate *TIntermAggregate::Create(const TType &type,
314 TOperator op,
315 TIntermSequence *arguments)
316{
Olli Etuahofe486322017-03-21 09:30:54 +0000317 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400318 ASSERT(op != EOpCallInternalRawFunction); // Should use CreateRawFunctionCall
Olli Etuahofe486322017-03-21 09:30:54 +0000319 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400320 ASSERT(op != EOpConstruct); // Should use CreateConstructor
321 return new TIntermAggregate(nullptr, type, op, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000322}
323
Olli Etuaho0c371002017-12-13 17:00:25 +0400324TIntermAggregate::TIntermAggregate(const TFunction *func,
325 const TType &type,
326 TOperator op,
327 TIntermSequence *arguments)
328 : TIntermOperator(op),
329 mUseEmulatedFunction(false),
330 mGotPrecisionFromChildren(false),
331 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800332{
333 if (arguments != nullptr)
334 {
335 mArguments.swap(*arguments);
336 }
Olli Etuaho1bb85282017-12-14 13:39:53 +0200337 ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800338 setTypePrecisionAndQualifier(type);
339}
340
341void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
342{
343 setType(type);
344 mType.setQualifier(EvqTemporary);
345 if (!isFunctionCall())
346 {
347 if (isConstructor())
348 {
349 // Structs should not be precision qualified, the individual members may be.
350 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300351 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800352 {
353 setPrecisionFromChildren();
354 }
355 }
356 else
357 {
358 setPrecisionForBuiltInOp();
359 }
360 if (areChildrenConstQualified())
361 {
362 mType.setQualifier(EvqConst);
363 }
364 }
365}
366
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200367bool TIntermAggregate::areChildrenConstQualified()
368{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800369 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200370 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800371 TIntermTyped *typedArg = arg->getAsTyped();
372 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200373 {
374 return false;
375 }
376 }
377 return true;
378}
379
Olli Etuahod2a67b92014-10-21 16:42:57 +0300380void TIntermAggregate::setPrecisionFromChildren()
381{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300382 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300383 if (getBasicType() == EbtBool)
384 {
385 mType.setPrecision(EbpUndefined);
386 return;
387 }
388
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500389 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800390 TIntermSequence::iterator childIter = mArguments.begin();
391 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300392 {
393 TIntermTyped *typed = (*childIter)->getAsTyped();
394 if (typed)
395 precision = GetHigherPrecision(typed->getPrecision(), precision);
396 ++childIter;
397 }
398 mType.setPrecision(precision);
399}
400
Olli Etuaho9250cb22017-01-21 10:51:27 +0000401void TIntermAggregate::setPrecisionForBuiltInOp()
402{
403 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800404 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000405 if (!setPrecisionForSpecialBuiltInOp())
406 {
407 setPrecisionFromChildren();
408 }
409}
410
411bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
412{
413 switch (mOp)
414 {
415 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800416 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
417 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000418 return true;
419 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800420 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
421 mArguments[1]->getAsTyped()->getPrecision()));
422 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000423 return true;
424 case EOpUaddCarry:
425 case EOpUsubBorrow:
426 mType.setPrecision(EbpHigh);
427 return true;
428 default:
429 return false;
430 }
431}
432
Olli Etuahod2a67b92014-10-21 16:42:57 +0300433void TIntermAggregate::setBuiltInFunctionPrecision()
434{
435 // All built-ins returning bool should be handled as ops, not functions.
436 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800437 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300438
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800439 TPrecision precision = EbpUndefined;
440 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300441 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800442 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300443 // ESSL spec section 8: texture functions get their precision from the sampler.
444 if (typed && IsSampler(typed->getBasicType()))
445 {
446 precision = typed->getPrecision();
447 break;
448 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300449 }
450 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
451 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobed35d72017-12-20 16:36:26 +0200452 if (mFunction->name().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300453 mType.setPrecision(EbpHigh);
454 else
455 mType.setPrecision(precision);
456}
457
Olli Etuahof2209f72017-04-01 12:45:55 +0300458TString TIntermAggregate::getSymbolTableMangledName() const
459{
460 ASSERT(!isConstructor());
461 switch (mOp)
462 {
463 case EOpCallInternalRawFunction:
464 case EOpCallBuiltInFunction:
465 case EOpCallFunctionInAST:
Olli Etuahobed35d72017-12-20 16:36:26 +0200466 return TFunction::GetMangledNameFromCall(mFunction->name(), mArguments);
Olli Etuahof2209f72017-04-01 12:45:55 +0300467 default:
468 TString opString = GetOperatorString(mOp);
469 return TFunction::GetMangledNameFromCall(opString, mArguments);
470 }
471}
472
Olli Etuaho0c371002017-12-13 17:00:25 +0400473const char *TIntermAggregate::functionName() const
474{
475 ASSERT(!isConstructor());
476 switch (mOp)
477 {
478 case EOpCallInternalRawFunction:
479 case EOpCallBuiltInFunction:
480 case EOpCallFunctionInAST:
Olli Etuahobed35d72017-12-20 16:36:26 +0200481 return mFunction->name().c_str();
Olli Etuaho0c371002017-12-13 17:00:25 +0400482 default:
483 return GetOperatorString(mOp);
484 }
485}
486
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300487bool TIntermAggregate::hasSideEffects() const
488{
Olli Etuaho0c371002017-12-13 17:00:25 +0400489 if (isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300490 {
491 for (TIntermNode *arg : mArguments)
492 {
493 if (arg->getAsTyped()->hasSideEffects())
494 {
495 return true;
496 }
497 }
498 return false;
499 }
500 // Conservatively assume most aggregate operators have side-effects
501 return true;
502}
503
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100504void TIntermBlock::appendStatement(TIntermNode *statement)
505{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300506 // Declaration nodes with no children can appear if it was an empty declaration or if all the
507 // declarators just added constants to the symbol table instead of generating code. We still
508 // need to add the declaration to the AST in that case because it might be relevant to the
509 // validity of switch/case.
510 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100511 {
512 mStatements.push_back(statement);
513 }
514}
515
Olli Etuaho16c745a2017-01-16 17:02:27 +0000516void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
517{
518 ASSERT(parameter != nullptr);
519 mParameters.push_back(parameter);
520}
521
Olli Etuaho13389b62016-10-16 11:48:18 +0100522void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
523{
524 ASSERT(declarator != nullptr);
525 ASSERT(declarator->getAsSymbolNode() != nullptr ||
526 (declarator->getAsBinaryNode() != nullptr &&
527 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
528 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300529 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100530 mDeclarators.push_back(declarator);
531}
532
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300533bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
534{
535 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
536 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
537 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
538 return false;
539}
540
Olli Etuaho57961272016-09-14 13:57:46 +0300541bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400542{
543 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100544 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
545 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400546 return false;
547}
548
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500549bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200550{
551 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100552 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300553 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200554 return false;
555}
556
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500557bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200558{
559 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
560 return false;
561}
562
Olli Etuahod7a25242015-08-18 13:49:45 +0300563TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
564{
565 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
566 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
567 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
568 mLine = node.mLine;
569}
570
Olli Etuahod4f4c112016-04-15 15:11:24 +0300571bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
572{
573 TIntermAggregate *constructor = getAsAggregate();
574 if (!constructor || !constructor->isConstructor())
575 {
576 return false;
577 }
578 for (TIntermNode *&node : *constructor->getSequence())
579 {
580 if (!node->getAsConstantUnion())
581 return false;
582 }
583 return true;
584}
585
Olli Etuahod7a25242015-08-18 13:49:45 +0300586TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
587{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200588 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300589}
590
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200591TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
592 : TIntermTyped(function->getReturnType()), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100593{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200594 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100595}
596
Olli Etuahod7a25242015-08-18 13:49:45 +0300597TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
598 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300599 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100600 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400601 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300602{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800603 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300604 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800605 TIntermTyped *typedArg = arg->getAsTyped();
606 ASSERT(typedArg != nullptr);
607 TIntermTyped *argCopy = typedArg->deepCopy();
608 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300609 }
610}
611
Olli Etuahofe486322017-03-21 09:30:54 +0000612TIntermAggregate *TIntermAggregate::shallowCopy() const
613{
614 TIntermSequence *copySeq = new TIntermSequence();
615 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400616 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000617 copyNode->setLine(mLine);
618 return copyNode;
619}
620
Olli Etuahob6fa0432016-09-28 16:28:05 +0100621TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
622{
623 TIntermTyped *operandCopy = node.mOperand->deepCopy();
624 ASSERT(operandCopy != nullptr);
625 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000626 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100627}
628
Olli Etuahod7a25242015-08-18 13:49:45 +0300629TIntermBinary::TIntermBinary(const TIntermBinary &node)
630 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
631{
632 TIntermTyped *leftCopy = node.mLeft->deepCopy();
633 TIntermTyped *rightCopy = node.mRight->deepCopy();
634 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
635 mLeft = leftCopy;
636 mRight = rightCopy;
637}
638
639TIntermUnary::TIntermUnary(const TIntermUnary &node)
640 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
641{
642 TIntermTyped *operandCopy = node.mOperand->deepCopy();
643 ASSERT(operandCopy != nullptr);
644 mOperand = operandCopy;
645}
646
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300647TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300648{
Olli Etuahod7a25242015-08-18 13:49:45 +0300649 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300650 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
651 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300652 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300653 mCondition = conditionCopy;
654 mTrueExpression = trueCopy;
655 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300656}
657
Jamie Madillb1a85f42014-08-19 15:23:24 -0400658bool TIntermOperator::isAssignment() const
659{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300660 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400661}
662
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300663bool TIntermOperator::isMultiplication() const
664{
665 switch (mOp)
666 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500667 case EOpMul:
668 case EOpMatrixTimesMatrix:
669 case EOpMatrixTimesVector:
670 case EOpMatrixTimesScalar:
671 case EOpVectorTimesMatrix:
672 case EOpVectorTimesScalar:
673 return true;
674 default:
675 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300676 }
677}
678
Jamie Madillb1a85f42014-08-19 15:23:24 -0400679bool TIntermOperator::isConstructor() const
680{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300681 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400682}
683
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800684bool TIntermOperator::isFunctionCall() const
685{
686 switch (mOp)
687 {
688 case EOpCallFunctionInAST:
689 case EOpCallBuiltInFunction:
690 case EOpCallInternalRawFunction:
691 return true;
692 default:
693 return false;
694 }
695}
696
Olli Etuaho1dded802016-08-18 18:13:13 +0300697TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
698{
699 if (left.isMatrix())
700 {
701 if (right.isMatrix())
702 {
703 return EOpMatrixTimesMatrix;
704 }
705 else
706 {
707 if (right.isVector())
708 {
709 return EOpMatrixTimesVector;
710 }
711 else
712 {
713 return EOpMatrixTimesScalar;
714 }
715 }
716 }
717 else
718 {
719 if (right.isMatrix())
720 {
721 if (left.isVector())
722 {
723 return EOpVectorTimesMatrix;
724 }
725 else
726 {
727 return EOpMatrixTimesScalar;
728 }
729 }
730 else
731 {
732 // Neither operand is a matrix.
733 if (left.isVector() == right.isVector())
734 {
735 // Leave as component product.
736 return EOpMul;
737 }
738 else
739 {
740 return EOpVectorTimesScalar;
741 }
742 }
743 }
744}
745
746TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
747{
748 if (left.isMatrix())
749 {
750 if (right.isMatrix())
751 {
752 return EOpMatrixTimesMatrixAssign;
753 }
754 else
755 {
756 // right should be scalar, but this may not be validated yet.
757 return EOpMatrixTimesScalarAssign;
758 }
759 }
760 else
761 {
762 if (right.isMatrix())
763 {
764 // Left should be a vector, but this may not be validated yet.
765 return EOpVectorTimesMatrixAssign;
766 }
767 else
768 {
769 // Neither operand is a matrix.
770 if (left.isVector() == right.isVector())
771 {
772 // Leave as component product.
773 return EOpMulAssign;
774 }
775 else
776 {
777 // left should be vector and right should be scalar, but this may not be validated
778 // yet.
779 return EOpVectorTimesScalarAssign;
780 }
781 }
782 }
783}
784
Jamie Madillb1a85f42014-08-19 15:23:24 -0400785//
786// Make sure the type of a unary operator is appropriate for its
787// combination of operation and operand type.
788//
Olli Etuahoa2234302016-08-31 12:05:39 +0300789void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400790{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300791 if (mOp == EOpArrayLength)
792 {
793 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
794 setType(TType(EbtInt, EbpUndefined, EvqConst));
795 return;
796 }
797
Olli Etuahoa2234302016-08-31 12:05:39 +0300798 TQualifier resultQualifier = EvqTemporary;
799 if (mOperand->getQualifier() == EvqConst)
800 resultQualifier = EvqConst;
801
802 unsigned char operandPrimarySize =
803 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400804 switch (mOp)
805 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300806 case EOpFloatBitsToInt:
807 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
808 break;
809 case EOpFloatBitsToUint:
810 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
811 break;
812 case EOpIntBitsToFloat:
813 case EOpUintBitsToFloat:
814 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
815 break;
816 case EOpPackSnorm2x16:
817 case EOpPackUnorm2x16:
818 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800819 case EOpPackUnorm4x8:
820 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300821 setType(TType(EbtUInt, EbpHigh, resultQualifier));
822 break;
823 case EOpUnpackSnorm2x16:
824 case EOpUnpackUnorm2x16:
825 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
826 break;
827 case EOpUnpackHalf2x16:
828 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
829 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800830 case EOpUnpackUnorm4x8:
831 case EOpUnpackSnorm4x8:
832 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
833 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300834 case EOpAny:
835 case EOpAll:
836 setType(TType(EbtBool, EbpUndefined, resultQualifier));
837 break;
838 case EOpLength:
839 case EOpDeterminant:
840 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
841 break;
842 case EOpTranspose:
843 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
844 static_cast<unsigned char>(mOperand->getType().getRows()),
845 static_cast<unsigned char>(mOperand->getType().getCols())));
846 break;
847 case EOpIsInf:
848 case EOpIsNan:
849 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
850 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000851 case EOpBitfieldReverse:
852 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
853 break;
854 case EOpBitCount:
855 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
856 break;
857 case EOpFindLSB:
858 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
859 break;
860 case EOpFindMSB:
861 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
862 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300863 default:
864 setType(mOperand->getType());
865 mType.setQualifier(resultQualifier);
866 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400867 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300868}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400869
Olli Etuahob6fa0432016-09-28 16:28:05 +0100870TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
871 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
872 mOperand(operand),
873 mSwizzleOffsets(swizzleOffsets)
874{
875 ASSERT(mSwizzleOffsets.size() <= 4);
876 promote();
877}
878
Olli Etuahoa2234302016-08-31 12:05:39 +0300879TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
880 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
881{
882 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400883}
884
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300885TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
886 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
887{
888 promote();
889}
890
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000891TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
892 : TIntermNode(), mSymbol(symbol)
893{
894 ASSERT(symbol);
895 setLine(line);
896}
897
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300898TIntermTernary::TIntermTernary(TIntermTyped *cond,
899 TIntermTyped *trueExpression,
900 TIntermTyped *falseExpression)
901 : TIntermTyped(trueExpression->getType()),
902 mCondition(cond),
903 mTrueExpression(trueExpression),
904 mFalseExpression(falseExpression)
905{
906 getTypePointer()->setQualifier(
907 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
908}
909
Olli Etuaho81629262017-04-19 11:56:01 +0300910TIntermLoop::TIntermLoop(TLoopType type,
911 TIntermNode *init,
912 TIntermTyped *cond,
913 TIntermTyped *expr,
914 TIntermBlock *body)
915 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
916{
917 // Declaration nodes with no children can appear if all the declarators just added constants to
918 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
919 if (mInit && mInit->getAsDeclarationNode() &&
920 mInit->getAsDeclarationNode()->getSequence()->empty())
921 {
922 mInit = nullptr;
923 }
924}
925
Olli Etuaho923ecef2017-10-11 12:01:38 +0300926TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
927 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
928{
929 // Prune empty false blocks so that there won't be unnecessary operations done on it.
930 if (mFalseBlock && mFalseBlock->getSequence()->empty())
931 {
932 mFalseBlock = nullptr;
933 }
934}
935
936TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
937 : TIntermNode(), mInit(init), mStatementList(statementList)
938{
939 ASSERT(mStatementList);
940}
941
942void TIntermSwitch::setStatementList(TIntermBlock *statementList)
943{
944 ASSERT(statementList);
945 mStatementList = statementList;
946}
947
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300948// static
949TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
950 TIntermTyped *trueExpression,
951 TIntermTyped *falseExpression)
952{
953 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
954 falseExpression->getQualifier() == EvqConst)
955 {
956 return EvqConst;
957 }
958 return EvqTemporary;
959}
960
Olli Etuahoeb7f90f2017-07-07 17:25:23 +0300961TIntermTyped *TIntermTernary::fold()
962{
963 if (mCondition->getAsConstantUnion())
964 {
965 if (mCondition->getAsConstantUnion()->getBConst(0))
966 {
967 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
968 return mTrueExpression;
969 }
970 else
971 {
972 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
973 return mFalseExpression;
974 }
975 }
976 return this;
977}
978
Olli Etuahob6fa0432016-09-28 16:28:05 +0100979void TIntermSwizzle::promote()
980{
981 TQualifier resultQualifier = EvqTemporary;
982 if (mOperand->getQualifier() == EvqConst)
983 resultQualifier = EvqConst;
984
985 auto numFields = mSwizzleOffsets.size();
986 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
987 static_cast<unsigned char>(numFields)));
988}
989
990bool TIntermSwizzle::hasDuplicateOffsets() const
991{
992 int offsetCount[4] = {0u, 0u, 0u, 0u};
993 for (const auto offset : mSwizzleOffsets)
994 {
995 offsetCount[offset]++;
996 if (offsetCount[offset] > 1)
997 {
998 return true;
999 }
1000 }
1001 return false;
1002}
1003
Olli Etuaho09b04a22016-12-15 13:30:26 +00001004bool TIntermSwizzle::offsetsMatch(int offset) const
1005{
1006 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1007}
1008
Olli Etuahob6fa0432016-09-28 16:28:05 +01001009void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1010{
1011 for (const int offset : mSwizzleOffsets)
1012 {
1013 switch (offset)
1014 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001015 case 0:
1016 *out << "x";
1017 break;
1018 case 1:
1019 *out << "y";
1020 break;
1021 case 2:
1022 *out << "z";
1023 break;
1024 case 3:
1025 *out << "w";
1026 break;
1027 default:
1028 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001029 }
1030 }
1031}
1032
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001033TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1034 const TIntermTyped *left,
1035 const TIntermTyped *right)
1036{
1037 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1038 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1039 right->getQualifier() != EvqConst)
1040 {
1041 return EvqTemporary;
1042 }
1043 return EvqConst;
1044}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001045
1046// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001047void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001048{
Olli Etuaho1dded802016-08-18 18:13:13 +03001049 ASSERT(!isMultiplication() ||
1050 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1051
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001052 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1053 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001054 if (mOp == EOpComma)
1055 {
1056 setType(mRight->getType());
1057 return;
1058 }
1059
Jamie Madillb1a85f42014-08-19 15:23:24 -04001060 // Base assumption: just make the type the same as the left
1061 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001062 setType(mLeft->getType());
1063
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001064 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001065 // Binary operations results in temporary variables unless both
1066 // operands are const.
1067 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1068 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001069 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001070 getTypePointer()->setQualifier(EvqTemporary);
1071 }
1072
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001073 // Handle indexing ops.
1074 switch (mOp)
1075 {
1076 case EOpIndexDirect:
1077 case EOpIndexIndirect:
1078 if (mLeft->isArray())
1079 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001080 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001081 }
1082 else if (mLeft->isMatrix())
1083 {
1084 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1085 static_cast<unsigned char>(mLeft->getRows())));
1086 }
1087 else if (mLeft->isVector())
1088 {
1089 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1090 }
1091 else
1092 {
1093 UNREACHABLE();
1094 }
1095 return;
1096 case EOpIndexDirectStruct:
1097 {
1098 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1099 const int i = mRight->getAsConstantUnion()->getIConst(0);
1100 setType(*fields[i]->type());
1101 getTypePointer()->setQualifier(resultQualifier);
1102 return;
1103 }
1104 case EOpIndexDirectInterfaceBlock:
1105 {
1106 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1107 const int i = mRight->getAsConstantUnion()->getIConst(0);
1108 setType(*fields[i]->type());
1109 getTypePointer()->setQualifier(resultQualifier);
1110 return;
1111 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001112 default:
1113 break;
1114 }
1115
1116 ASSERT(mLeft->isArray() == mRight->isArray());
1117
1118 // The result gets promoted to the highest precision.
1119 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1120 getTypePointer()->setPrecision(higherPrecision);
1121
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001122 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001123
1124 //
1125 // All scalars or structs. Code after this test assumes this case is removed!
1126 //
1127 if (nominalSize == 1)
1128 {
1129 switch (mOp)
1130 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001131 //
1132 // Promote to conditional
1133 //
1134 case EOpEqual:
1135 case EOpNotEqual:
1136 case EOpLessThan:
1137 case EOpGreaterThan:
1138 case EOpLessThanEqual:
1139 case EOpGreaterThanEqual:
1140 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1141 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001142
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001143 //
1144 // And and Or operate on conditionals
1145 //
1146 case EOpLogicalAnd:
1147 case EOpLogicalXor:
1148 case EOpLogicalOr:
1149 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1150 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1151 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001152
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001153 default:
1154 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001155 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001156 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001157 }
1158
1159 // If we reach here, at least one of the operands is vector or matrix.
1160 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001161 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001162
Jamie Madillb1a85f42014-08-19 15:23:24 -04001163 switch (mOp)
1164 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001165 case EOpMul:
1166 break;
1167 case EOpMatrixTimesScalar:
1168 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001169 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001170 setType(TType(basicType, higherPrecision, resultQualifier,
1171 static_cast<unsigned char>(mRight->getCols()),
1172 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001173 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001174 break;
1175 case EOpMatrixTimesVector:
1176 setType(TType(basicType, higherPrecision, resultQualifier,
1177 static_cast<unsigned char>(mLeft->getRows()), 1));
1178 break;
1179 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001180 setType(TType(basicType, higherPrecision, resultQualifier,
1181 static_cast<unsigned char>(mRight->getCols()),
1182 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001183 break;
1184 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001185 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001186 static_cast<unsigned char>(nominalSize), 1));
1187 break;
1188 case EOpVectorTimesMatrix:
1189 setType(TType(basicType, higherPrecision, resultQualifier,
1190 static_cast<unsigned char>(mRight->getCols()), 1));
1191 break;
1192 case EOpMulAssign:
1193 case EOpVectorTimesScalarAssign:
1194 case EOpVectorTimesMatrixAssign:
1195 case EOpMatrixTimesScalarAssign:
1196 case EOpMatrixTimesMatrixAssign:
1197 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1198 break;
1199 case EOpAssign:
1200 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001201 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1202 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1203 break;
1204 case EOpAdd:
1205 case EOpSub:
1206 case EOpDiv:
1207 case EOpIMod:
1208 case EOpBitShiftLeft:
1209 case EOpBitShiftRight:
1210 case EOpBitwiseAnd:
1211 case EOpBitwiseXor:
1212 case EOpBitwiseOr:
1213 case EOpAddAssign:
1214 case EOpSubAssign:
1215 case EOpDivAssign:
1216 case EOpIModAssign:
1217 case EOpBitShiftLeftAssign:
1218 case EOpBitShiftRightAssign:
1219 case EOpBitwiseAndAssign:
1220 case EOpBitwiseXorAssign:
1221 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001222 {
1223 const int secondarySize =
1224 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1225 setType(TType(basicType, higherPrecision, resultQualifier,
1226 static_cast<unsigned char>(nominalSize),
1227 static_cast<unsigned char>(secondarySize)));
1228 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001229 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001230 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001231 case EOpEqual:
1232 case EOpNotEqual:
1233 case EOpLessThan:
1234 case EOpGreaterThan:
1235 case EOpLessThanEqual:
1236 case EOpGreaterThanEqual:
1237 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1238 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001239 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001240 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001241
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001242 case EOpIndexDirect:
1243 case EOpIndexIndirect:
1244 case EOpIndexDirectInterfaceBlock:
1245 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001246 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001247 UNREACHABLE();
1248 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001249 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001250 UNREACHABLE();
1251 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001252 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001253}
1254
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001255const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001256{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001257 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001258 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001259 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001260 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001261 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001262 size_t arrayElementSize = arrayElementType.getObjectSize();
1263 return &mUnionArrayPointer[arrayElementSize * index];
1264 }
1265 else if (isMatrix())
1266 {
1267 ASSERT(index < getType().getCols());
1268 int size = getType().getRows();
1269 return &mUnionArrayPointer[size * index];
1270 }
1271 else if (isVector())
1272 {
1273 ASSERT(index < getType().getNominalSize());
1274 return &mUnionArrayPointer[index];
1275 }
1276 else
1277 {
1278 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001279 return nullptr;
1280 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001281}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001282
Olli Etuahob6fa0432016-09-28 16:28:05 +01001283TIntermTyped *TIntermSwizzle::fold()
1284{
1285 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1286 if (operandConstant == nullptr)
1287 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001288 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001289 }
1290
1291 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1292 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1293 {
1294 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1295 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001296 return CreateFoldedNode(constArray, this);
Olli Etuahob6fa0432016-09-28 16:28:05 +01001297}
1298
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001299TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1300{
1301 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1302 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1303 switch (mOp)
1304 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001305 case EOpComma:
1306 {
1307 if (mLeft->hasSideEffects())
1308 {
1309 return this;
1310 }
1311 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1312 return mRight;
1313 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001314 case EOpIndexDirect:
1315 {
1316 if (leftConstant == nullptr || rightConstant == nullptr)
1317 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001318 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001319 }
1320 int index = rightConstant->getIConst(0);
1321
1322 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001323 if (!constArray)
1324 {
1325 return this;
1326 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001327 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001328 }
1329 case EOpIndexDirectStruct:
1330 {
1331 if (leftConstant == nullptr || rightConstant == nullptr)
1332 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001333 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001334 }
1335 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1336 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1337
1338 size_t previousFieldsSize = 0;
1339 for (size_t i = 0; i < index; ++i)
1340 {
1341 previousFieldsSize += fields[i]->type()->getObjectSize();
1342 }
1343
1344 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
Olli Etuaho2768bc82017-12-12 11:51:48 +02001345 return CreateFoldedNode(constArray + previousFieldsSize, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001346 }
1347 case EOpIndexIndirect:
1348 case EOpIndexDirectInterfaceBlock:
1349 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001350 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001351 default:
1352 {
1353 if (leftConstant == nullptr || rightConstant == nullptr)
1354 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001355 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001356 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001357 TConstantUnion *constArray =
1358 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001359 if (!constArray)
1360 {
1361 return this;
1362 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001363 return CreateFoldedNode(constArray, this);
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001364 }
1365 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001366}
1367
Olli Etuahof119a262016-08-19 15:54:22 +03001368TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001369{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301370 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001371
1372 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301373 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001374 // The size of runtime-sized arrays may only be determined at runtime.
1375 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001376 {
1377 return this;
1378 }
1379 constArray = new TConstantUnion[1];
1380 constArray->setIConst(mOperand->getOutermostArraySize());
1381 }
1382 else
1383 {
1384 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1385 if (operandConstant == nullptr)
1386 {
1387 return this;
1388 }
1389
1390 switch (mOp)
1391 {
1392 case EOpAny:
1393 case EOpAll:
1394 case EOpLength:
1395 case EOpTranspose:
1396 case EOpDeterminant:
1397 case EOpInverse:
1398 case EOpPackSnorm2x16:
1399 case EOpUnpackSnorm2x16:
1400 case EOpPackUnorm2x16:
1401 case EOpUnpackUnorm2x16:
1402 case EOpPackHalf2x16:
1403 case EOpUnpackHalf2x16:
1404 case EOpPackUnorm4x8:
1405 case EOpPackSnorm4x8:
1406 case EOpUnpackUnorm4x8:
1407 case EOpUnpackSnorm4x8:
1408 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1409 break;
1410 default:
1411 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1412 break;
1413 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301414 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001415 if (constArray == nullptr)
1416 {
1417 return this;
1418 }
Olli Etuaho2768bc82017-12-12 11:51:48 +02001419 return CreateFoldedNode(constArray, this);
Olli Etuahob43846e2015-06-02 18:18:57 +03001420}
1421
Olli Etuahof119a262016-08-19 15:54:22 +03001422TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001423{
1424 // Make sure that all params are constant before actual constant folding.
1425 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001426 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001427 if (param->getAsConstantUnion() == nullptr)
1428 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001429 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001430 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001431 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001432 TConstantUnion *constArray = nullptr;
1433 if (isConstructor())
Olli Etuaho2768bc82017-12-12 11:51:48 +02001434 {
Olli Etuahof119a262016-08-19 15:54:22 +03001435 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001436 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001437 else
Olli Etuaho2768bc82017-12-12 11:51:48 +02001438 {
1439 ASSERT(CanFoldAggregateBuiltInOp(mOp));
Olli Etuahof119a262016-08-19 15:54:22 +03001440 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho2768bc82017-12-12 11:51:48 +02001441 }
1442 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +03001443}
1444
Jamie Madillb1a85f42014-08-19 15:23:24 -04001445//
1446// The fold functions see if an operation on a constant can be done in place,
1447// without generating run-time code.
1448//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001449// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001450//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001451TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1452 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001453 TDiagnostics *diagnostics,
1454 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001455{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001456 const TConstantUnion *leftArray = getUnionArrayPointer();
1457 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001458
Olli Etuahof119a262016-08-19 15:54:22 +03001459 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001460
1461 size_t objectSize = getType().getObjectSize();
1462
1463 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1464 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1465 {
1466 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1467 }
1468 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1469 {
1470 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001471 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001472 objectSize = rightNode->getType().getObjectSize();
1473 }
1474
1475 TConstantUnion *resultArray = nullptr;
1476
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001477 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001478 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001479 case EOpAdd:
1480 resultArray = new TConstantUnion[objectSize];
1481 for (size_t i = 0; i < objectSize; i++)
1482 resultArray[i] =
1483 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1484 break;
1485 case EOpSub:
1486 resultArray = new TConstantUnion[objectSize];
1487 for (size_t i = 0; i < objectSize; i++)
1488 resultArray[i] =
1489 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1490 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001491
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001492 case EOpMul:
1493 case EOpVectorTimesScalar:
1494 case EOpMatrixTimesScalar:
1495 resultArray = new TConstantUnion[objectSize];
1496 for (size_t i = 0; i < objectSize; i++)
1497 resultArray[i] =
1498 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1499 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001500
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001501 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001502 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001503 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001504 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001505
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001506 const int leftCols = getCols();
1507 const int leftRows = getRows();
1508 const int rightCols = rightNode->getType().getCols();
1509 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001510 const int resultCols = rightCols;
1511 const int resultRows = leftRows;
1512
1513 resultArray = new TConstantUnion[resultCols * resultRows];
1514 for (int row = 0; row < resultRows; row++)
1515 {
1516 for (int column = 0; column < resultCols; column++)
1517 {
1518 resultArray[resultRows * column + row].setFConst(0.0f);
1519 for (int i = 0; i < leftCols; i++)
1520 {
1521 resultArray[resultRows * column + row].setFConst(
1522 resultArray[resultRows * column + row].getFConst() +
1523 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001524 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001525 }
1526 }
1527 }
1528 }
1529 break;
1530
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001531 case EOpDiv:
1532 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001533 {
1534 resultArray = new TConstantUnion[objectSize];
1535 for (size_t i = 0; i < objectSize; i++)
1536 {
1537 switch (getType().getBasicType())
1538 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001539 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001540 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001541 ASSERT(op == EOpDiv);
1542 float dividend = leftArray[i].getFConst();
1543 float divisor = rightArray[i].getFConst();
1544 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001545 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001546 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001547 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001548 diagnostics->warning(
1549 getLine(),
1550 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001551 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001552 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001553 }
1554 else
1555 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001556 diagnostics->warning(getLine(),
1557 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001558 bool negativeResult =
1559 std::signbit(dividend) != std::signbit(divisor);
1560 resultArray[i].setFConst(
1561 negativeResult ? -std::numeric_limits<float>::infinity()
1562 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001563 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001564 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001565 else if (gl::isInf(dividend) && gl::isInf(divisor))
1566 {
1567 diagnostics->warning(getLine(),
1568 "Infinity divided by infinity during constant "
1569 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001570 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001571 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1572 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001573 else
1574 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001575 float result = dividend / divisor;
1576 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001577 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001578 diagnostics->warning(
1579 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001580 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001581 }
1582 resultArray[i].setFConst(result);
1583 }
1584 break;
1585 }
1586 case EbtInt:
1587 if (rightArray[i] == 0)
1588 {
1589 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001590 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001591 resultArray[i].setIConst(INT_MAX);
1592 }
1593 else
1594 {
1595 int lhs = leftArray[i].getIConst();
1596 int divisor = rightArray[i].getIConst();
1597 if (op == EOpDiv)
1598 {
1599 // Check for the special case where the minimum representable number
1600 // is
1601 // divided by -1. If left alone this leads to integer overflow in
1602 // C++.
1603 // ESSL 3.00.6 section 4.1.3 Integers:
1604 // "However, for the case where the minimum representable value is
1605 // divided by -1, it is allowed to return either the minimum
1606 // representable value or the maximum representable value."
1607 if (lhs == -0x7fffffff - 1 && divisor == -1)
1608 {
1609 resultArray[i].setIConst(0x7fffffff);
1610 }
1611 else
1612 {
1613 resultArray[i].setIConst(lhs / divisor);
1614 }
Olli Etuahod4453572016-09-27 13:21:46 +01001615 }
1616 else
1617 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 ASSERT(op == EOpIMod);
1619 if (lhs < 0 || divisor < 0)
1620 {
1621 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1622 // when
1623 // either one of the operands is negative.
1624 diagnostics->warning(getLine(),
1625 "Negative modulus operator operand "
1626 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001627 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001628 resultArray[i].setIConst(0);
1629 }
1630 else
1631 {
1632 resultArray[i].setIConst(lhs % divisor);
1633 }
Olli Etuahod4453572016-09-27 13:21:46 +01001634 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001635 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001636 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001637
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001638 case EbtUInt:
1639 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001640 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001641 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001642 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001643 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001644 }
1645 else
1646 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001647 if (op == EOpDiv)
1648 {
1649 resultArray[i].setUConst(leftArray[i].getUConst() /
1650 rightArray[i].getUConst());
1651 }
1652 else
1653 {
1654 ASSERT(op == EOpIMod);
1655 resultArray[i].setUConst(leftArray[i].getUConst() %
1656 rightArray[i].getUConst());
1657 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001658 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001659 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001660
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001661 default:
1662 UNREACHABLE();
1663 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001664 }
1665 }
1666 }
1667 break;
1668
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001669 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001670 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001671 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001672 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001673
1674 const int matrixCols = getCols();
1675 const int matrixRows = getRows();
1676
1677 resultArray = new TConstantUnion[matrixRows];
1678
1679 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1680 {
1681 resultArray[matrixRow].setFConst(0.0f);
1682 for (int col = 0; col < matrixCols; col++)
1683 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001684 resultArray[matrixRow].setFConst(
1685 resultArray[matrixRow].getFConst() +
1686 leftArray[col * matrixRows + matrixRow].getFConst() *
1687 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001688 }
1689 }
1690 }
1691 break;
1692
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001693 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001694 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001695 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001696 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001697
1698 const int matrixCols = rightNode->getType().getCols();
1699 const int matrixRows = rightNode->getType().getRows();
1700
1701 resultArray = new TConstantUnion[matrixCols];
1702
1703 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1704 {
1705 resultArray[matrixCol].setFConst(0.0f);
1706 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1707 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001708 resultArray[matrixCol].setFConst(
1709 resultArray[matrixCol].getFConst() +
1710 leftArray[matrixRow].getFConst() *
1711 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001712 }
1713 }
1714 }
1715 break;
1716
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001717 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001718 {
1719 resultArray = new TConstantUnion[objectSize];
1720 for (size_t i = 0; i < objectSize; i++)
1721 {
1722 resultArray[i] = leftArray[i] && rightArray[i];
1723 }
1724 }
1725 break;
1726
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001727 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001728 {
1729 resultArray = new TConstantUnion[objectSize];
1730 for (size_t i = 0; i < objectSize; i++)
1731 {
1732 resultArray[i] = leftArray[i] || rightArray[i];
1733 }
1734 }
1735 break;
1736
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001737 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001738 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001739 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001740 resultArray = new TConstantUnion[objectSize];
1741 for (size_t i = 0; i < objectSize; i++)
1742 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001743 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001744 }
1745 }
1746 break;
1747
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001748 case EOpBitwiseAnd:
1749 resultArray = new TConstantUnion[objectSize];
1750 for (size_t i = 0; i < objectSize; i++)
1751 resultArray[i] = leftArray[i] & rightArray[i];
1752 break;
1753 case EOpBitwiseXor:
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 EOpBitwiseOr:
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 EOpBitShiftLeft:
1764 resultArray = new TConstantUnion[objectSize];
1765 for (size_t i = 0; i < objectSize; i++)
1766 resultArray[i] =
1767 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1768 break;
1769 case EOpBitShiftRight:
1770 resultArray = new TConstantUnion[objectSize];
1771 for (size_t i = 0; i < objectSize; i++)
1772 resultArray[i] =
1773 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1774 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001775
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001776 case EOpLessThan:
1777 ASSERT(objectSize == 1);
1778 resultArray = new TConstantUnion[1];
1779 resultArray->setBConst(*leftArray < *rightArray);
1780 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001781
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001782 case EOpGreaterThan:
1783 ASSERT(objectSize == 1);
1784 resultArray = new TConstantUnion[1];
1785 resultArray->setBConst(*leftArray > *rightArray);
1786 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001787
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001788 case EOpLessThanEqual:
1789 ASSERT(objectSize == 1);
1790 resultArray = new TConstantUnion[1];
1791 resultArray->setBConst(!(*leftArray > *rightArray));
1792 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001793
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001794 case EOpGreaterThanEqual:
1795 ASSERT(objectSize == 1);
1796 resultArray = new TConstantUnion[1];
1797 resultArray->setBConst(!(*leftArray < *rightArray));
1798 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001799
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001800 case EOpEqual:
1801 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001802 {
1803 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001804 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001805 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001806 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001807 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001808 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001809 equal = false;
1810 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001811 }
1812 }
1813 if (op == EOpEqual)
1814 {
1815 resultArray->setBConst(equal);
1816 }
1817 else
1818 {
1819 resultArray->setBConst(!equal);
1820 }
1821 }
1822 break;
1823
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001824 default:
1825 UNREACHABLE();
1826 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001827 }
1828 return resultArray;
1829}
1830
Olli Etuahof119a262016-08-19 15:54:22 +03001831// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1832// code. Returns the constant value to keep using. Nullptr should not be returned.
1833TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001834{
Olli Etuahof119a262016-08-19 15:54:22 +03001835 // Do operations where the return type may have a different number of components compared to the
1836 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001837
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001838 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001839 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301840
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001841 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301842 TConstantUnion *resultArray = nullptr;
1843 switch (op)
1844 {
Olli Etuahof119a262016-08-19 15:54:22 +03001845 case EOpAny:
1846 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301847 resultArray = new TConstantUnion();
1848 resultArray->setBConst(false);
1849 for (size_t i = 0; i < objectSize; i++)
1850 {
1851 if (operandArray[i].getBConst())
1852 {
1853 resultArray->setBConst(true);
1854 break;
1855 }
1856 }
1857 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301858
Olli Etuahof119a262016-08-19 15:54:22 +03001859 case EOpAll:
1860 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301861 resultArray = new TConstantUnion();
1862 resultArray->setBConst(true);
1863 for (size_t i = 0; i < objectSize; i++)
1864 {
1865 if (!operandArray[i].getBConst())
1866 {
1867 resultArray->setBConst(false);
1868 break;
1869 }
1870 }
1871 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301872
Olli Etuahof119a262016-08-19 15:54:22 +03001873 case EOpLength:
1874 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301875 resultArray = new TConstantUnion();
1876 resultArray->setFConst(VectorLength(operandArray, objectSize));
1877 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301878
Olli Etuahof119a262016-08-19 15:54:22 +03001879 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301880 {
Olli Etuahof119a262016-08-19 15:54:22 +03001881 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301882 resultArray = new TConstantUnion[objectSize];
1883 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001884 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301885 SetUnionArrayFromMatrix(result, resultArray);
1886 break;
1887 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301888
Olli Etuahof119a262016-08-19 15:54:22 +03001889 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301890 {
Olli Etuahof119a262016-08-19 15:54:22 +03001891 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301892 unsigned int size = getType().getNominalSize();
1893 ASSERT(size >= 2 && size <= 4);
1894 resultArray = new TConstantUnion();
1895 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1896 break;
1897 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301898
Olli Etuahof119a262016-08-19 15:54:22 +03001899 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301900 {
Olli Etuahof119a262016-08-19 15:54:22 +03001901 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301902 unsigned int size = getType().getNominalSize();
1903 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001904 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301905 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1906 SetUnionArrayFromMatrix(result, resultArray);
1907 break;
1908 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301909
Olli Etuahof119a262016-08-19 15:54:22 +03001910 case EOpPackSnorm2x16:
1911 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301912 ASSERT(getType().getNominalSize() == 2);
1913 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001914 resultArray->setUConst(
1915 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301916 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301917
Olli Etuahof119a262016-08-19 15:54:22 +03001918 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301919 {
Olli Etuahof119a262016-08-19 15:54:22 +03001920 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301921 resultArray = new TConstantUnion[2];
1922 float f1, f2;
1923 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1924 resultArray[0].setFConst(f1);
1925 resultArray[1].setFConst(f2);
1926 break;
1927 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301928
Olli Etuahof119a262016-08-19 15:54:22 +03001929 case EOpPackUnorm2x16:
1930 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301931 ASSERT(getType().getNominalSize() == 2);
1932 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001933 resultArray->setUConst(
1934 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301935 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301936
Olli Etuahof119a262016-08-19 15:54:22 +03001937 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301938 {
Olli Etuahof119a262016-08-19 15:54:22 +03001939 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301940 resultArray = new TConstantUnion[2];
1941 float f1, f2;
1942 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1943 resultArray[0].setFConst(f1);
1944 resultArray[1].setFConst(f2);
1945 break;
1946 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301947
Olli Etuahof119a262016-08-19 15:54:22 +03001948 case EOpPackHalf2x16:
1949 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301950 ASSERT(getType().getNominalSize() == 2);
1951 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001952 resultArray->setUConst(
1953 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301954 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301955
Olli Etuahof119a262016-08-19 15:54:22 +03001956 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301957 {
Olli Etuahof119a262016-08-19 15:54:22 +03001958 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301959 resultArray = new TConstantUnion[2];
1960 float f1, f2;
1961 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1962 resultArray[0].setFConst(f1);
1963 resultArray[1].setFConst(f2);
1964 break;
1965 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301966
Olli Etuaho25aef452017-01-29 16:15:44 -08001967 case EOpPackUnorm4x8:
1968 {
1969 ASSERT(getType().getBasicType() == EbtFloat);
1970 resultArray = new TConstantUnion();
1971 resultArray->setUConst(
1972 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1973 operandArray[2].getFConst(), operandArray[3].getFConst()));
1974 break;
1975 }
1976 case EOpPackSnorm4x8:
1977 {
1978 ASSERT(getType().getBasicType() == EbtFloat);
1979 resultArray = new TConstantUnion();
1980 resultArray->setUConst(
1981 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1982 operandArray[2].getFConst(), operandArray[3].getFConst()));
1983 break;
1984 }
1985 case EOpUnpackUnorm4x8:
1986 {
1987 ASSERT(getType().getBasicType() == EbtUInt);
1988 resultArray = new TConstantUnion[4];
1989 float f[4];
1990 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
1991 for (size_t i = 0; i < 4; ++i)
1992 {
1993 resultArray[i].setFConst(f[i]);
1994 }
1995 break;
1996 }
1997 case EOpUnpackSnorm4x8:
1998 {
1999 ASSERT(getType().getBasicType() == EbtUInt);
2000 resultArray = new TConstantUnion[4];
2001 float f[4];
2002 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2003 for (size_t i = 0; i < 4; ++i)
2004 {
2005 resultArray[i].setFConst(f[i]);
2006 }
2007 break;
2008 }
2009
Olli Etuahof119a262016-08-19 15:54:22 +03002010 default:
2011 UNREACHABLE();
2012 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302013 }
2014
2015 return resultArray;
2016}
2017
Olli Etuahof119a262016-08-19 15:54:22 +03002018TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2019 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302020{
Olli Etuahof119a262016-08-19 15:54:22 +03002021 // Do unary operations where each component of the result is computed based on the corresponding
2022 // component of the operand. Also folds normalize, though the divisor in that case takes all
2023 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302024
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002025 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002026 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002027
2028 size_t objectSize = getType().getObjectSize();
2029
Arun Patoleab2b9a22015-07-06 18:27:56 +05302030 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2031 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302032 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002033 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302034 {
Olli Etuahof119a262016-08-19 15:54:22 +03002035 case EOpNegative:
2036 switch (getType().getBasicType())
2037 {
2038 case EbtFloat:
2039 resultArray[i].setFConst(-operandArray[i].getFConst());
2040 break;
2041 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002042 if (operandArray[i] == std::numeric_limits<int>::min())
2043 {
2044 // The minimum representable integer doesn't have a positive
2045 // counterpart, rather the negation overflows and in ESSL is supposed to
2046 // wrap back to the minimum representable integer. Make sure that we
2047 // don't actually let the negation overflow, which has undefined
2048 // behavior in C++.
2049 resultArray[i].setIConst(std::numeric_limits<int>::min());
2050 }
2051 else
2052 {
2053 resultArray[i].setIConst(-operandArray[i].getIConst());
2054 }
Olli Etuahof119a262016-08-19 15:54:22 +03002055 break;
2056 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002057 if (operandArray[i] == 0x80000000u)
2058 {
2059 resultArray[i].setUConst(0x80000000u);
2060 }
2061 else
2062 {
2063 resultArray[i].setUConst(static_cast<unsigned int>(
2064 -static_cast<int>(operandArray[i].getUConst())));
2065 }
Olli Etuahof119a262016-08-19 15:54:22 +03002066 break;
2067 default:
2068 UNREACHABLE();
2069 return nullptr;
2070 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302071 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302072
Olli Etuahof119a262016-08-19 15:54:22 +03002073 case EOpPositive:
2074 switch (getType().getBasicType())
2075 {
2076 case EbtFloat:
2077 resultArray[i].setFConst(operandArray[i].getFConst());
2078 break;
2079 case EbtInt:
2080 resultArray[i].setIConst(operandArray[i].getIConst());
2081 break;
2082 case EbtUInt:
2083 resultArray[i].setUConst(static_cast<unsigned int>(
2084 static_cast<int>(operandArray[i].getUConst())));
2085 break;
2086 default:
2087 UNREACHABLE();
2088 return nullptr;
2089 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302090 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302091
Olli Etuahof119a262016-08-19 15:54:22 +03002092 case EOpLogicalNot:
2093 switch (getType().getBasicType())
2094 {
2095 case EbtBool:
2096 resultArray[i].setBConst(!operandArray[i].getBConst());
2097 break;
2098 default:
2099 UNREACHABLE();
2100 return nullptr;
2101 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302102 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302103
Olli Etuahof119a262016-08-19 15:54:22 +03002104 case EOpBitwiseNot:
2105 switch (getType().getBasicType())
2106 {
2107 case EbtInt:
2108 resultArray[i].setIConst(~operandArray[i].getIConst());
2109 break;
2110 case EbtUInt:
2111 resultArray[i].setUConst(~operandArray[i].getUConst());
2112 break;
2113 default:
2114 UNREACHABLE();
2115 return nullptr;
2116 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302117 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302118
Olli Etuahof119a262016-08-19 15:54:22 +03002119 case EOpRadians:
2120 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302121 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2122 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302123
Olli Etuahof119a262016-08-19 15:54:22 +03002124 case EOpDegrees:
2125 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302126 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2127 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302128
Olli Etuahof119a262016-08-19 15:54:22 +03002129 case EOpSin:
2130 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302131 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302132
Olli Etuahof119a262016-08-19 15:54:22 +03002133 case EOpCos:
2134 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2135 break;
2136
2137 case EOpTan:
2138 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2139 break;
2140
2141 case EOpAsin:
2142 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2143 // 0.
2144 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2145 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2146 diagnostics, &resultArray[i]);
2147 else
2148 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2149 break;
2150
2151 case EOpAcos:
2152 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2153 // 0.
2154 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2155 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2156 diagnostics, &resultArray[i]);
2157 else
2158 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2159 break;
2160
2161 case EOpAtan:
2162 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2163 break;
2164
2165 case EOpSinh:
2166 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2167 break;
2168
2169 case EOpCosh:
2170 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2171 break;
2172
2173 case EOpTanh:
2174 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2175 break;
2176
2177 case EOpAsinh:
2178 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2179 break;
2180
2181 case EOpAcosh:
2182 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2183 if (operandArray[i].getFConst() < 1.0f)
2184 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2185 diagnostics, &resultArray[i]);
2186 else
2187 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2188 break;
2189
2190 case EOpAtanh:
2191 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2192 // 0.
2193 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2194 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2195 diagnostics, &resultArray[i]);
2196 else
2197 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2198 break;
2199
2200 case EOpAbs:
2201 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302202 {
Olli Etuahof119a262016-08-19 15:54:22 +03002203 case EbtFloat:
2204 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2205 break;
2206 case EbtInt:
2207 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2208 break;
2209 default:
2210 UNREACHABLE();
2211 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302212 }
2213 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002214
2215 case EOpSign:
2216 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302217 {
Olli Etuahof119a262016-08-19 15:54:22 +03002218 case EbtFloat:
2219 {
2220 float fConst = operandArray[i].getFConst();
2221 float fResult = 0.0f;
2222 if (fConst > 0.0f)
2223 fResult = 1.0f;
2224 else if (fConst < 0.0f)
2225 fResult = -1.0f;
2226 resultArray[i].setFConst(fResult);
2227 break;
2228 }
2229 case EbtInt:
2230 {
2231 int iConst = operandArray[i].getIConst();
2232 int iResult = 0;
2233 if (iConst > 0)
2234 iResult = 1;
2235 else if (iConst < 0)
2236 iResult = -1;
2237 resultArray[i].setIConst(iResult);
2238 break;
2239 }
2240 default:
2241 UNREACHABLE();
2242 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302243 }
2244 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302245
Olli Etuahof119a262016-08-19 15:54:22 +03002246 case EOpFloor:
2247 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2248 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302249
Olli Etuahof119a262016-08-19 15:54:22 +03002250 case EOpTrunc:
2251 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2252 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302253
Olli Etuahof119a262016-08-19 15:54:22 +03002254 case EOpRound:
2255 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2256 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302257
Olli Etuahof119a262016-08-19 15:54:22 +03002258 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302259 {
Olli Etuahof119a262016-08-19 15:54:22 +03002260 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302261 float x = operandArray[i].getFConst();
2262 float result;
2263 float fractPart = modff(x, &result);
2264 if (fabsf(fractPart) == 0.5f)
2265 result = 2.0f * roundf(x / 2.0f);
2266 else
2267 result = roundf(x);
2268 resultArray[i].setFConst(result);
2269 break;
2270 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302271
Olli Etuahof119a262016-08-19 15:54:22 +03002272 case EOpCeil:
2273 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2274 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302275
Olli Etuahof119a262016-08-19 15:54:22 +03002276 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302277 {
Olli Etuahof119a262016-08-19 15:54:22 +03002278 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302279 float x = operandArray[i].getFConst();
2280 resultArray[i].setFConst(x - floorf(x));
2281 break;
2282 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302283
Olli Etuahof119a262016-08-19 15:54:22 +03002284 case EOpIsNan:
2285 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302286 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2287 break;
Arun Patole551279e2015-07-07 18:18:23 +05302288
Olli Etuahof119a262016-08-19 15:54:22 +03002289 case EOpIsInf:
2290 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302291 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2292 break;
Arun Patole551279e2015-07-07 18:18:23 +05302293
Olli Etuahof119a262016-08-19 15:54:22 +03002294 case EOpFloatBitsToInt:
2295 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302296 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2297 break;
Arun Patole551279e2015-07-07 18:18:23 +05302298
Olli Etuahof119a262016-08-19 15:54:22 +03002299 case EOpFloatBitsToUint:
2300 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302301 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2302 break;
Arun Patole551279e2015-07-07 18:18:23 +05302303
Olli Etuahof119a262016-08-19 15:54:22 +03002304 case EOpIntBitsToFloat:
2305 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302306 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2307 break;
Arun Patole551279e2015-07-07 18:18:23 +05302308
Olli Etuahof119a262016-08-19 15:54:22 +03002309 case EOpUintBitsToFloat:
2310 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302311 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2312 break;
Arun Patole551279e2015-07-07 18:18:23 +05302313
Olli Etuahof119a262016-08-19 15:54:22 +03002314 case EOpExp:
2315 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2316 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302317
Olli Etuahof119a262016-08-19 15:54:22 +03002318 case EOpLog:
2319 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2320 if (operandArray[i].getFConst() <= 0.0f)
2321 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2322 diagnostics, &resultArray[i]);
2323 else
2324 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2325 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302326
Olli Etuahof119a262016-08-19 15:54:22 +03002327 case EOpExp2:
2328 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2329 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302330
Olli Etuahof119a262016-08-19 15:54:22 +03002331 case EOpLog2:
2332 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2333 // And log2f is not available on some plarforms like old android, so just using
2334 // log(x)/log(2) here.
2335 if (operandArray[i].getFConst() <= 0.0f)
2336 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2337 diagnostics, &resultArray[i]);
2338 else
2339 {
2340 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2341 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2342 }
2343 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302344
Olli Etuahof119a262016-08-19 15:54:22 +03002345 case EOpSqrt:
2346 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2347 if (operandArray[i].getFConst() < 0.0f)
2348 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2349 diagnostics, &resultArray[i]);
2350 else
2351 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2352 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302353
Olli Etuahof119a262016-08-19 15:54:22 +03002354 case EOpInverseSqrt:
2355 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2356 // so getting the square root first using builtin function sqrt() and then taking
2357 // its inverse.
2358 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2359 // result to 0.
2360 if (operandArray[i].getFConst() <= 0.0f)
2361 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2362 diagnostics, &resultArray[i]);
2363 else
2364 {
2365 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2366 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2367 }
2368 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302369
Olli Etuahod68924e2017-01-02 17:34:40 +00002370 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002371 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302372 resultArray[i].setBConst(!operandArray[i].getBConst());
2373 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302374
Olli Etuahof119a262016-08-19 15:54:22 +03002375 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302376 {
Olli Etuahof119a262016-08-19 15:54:22 +03002377 ASSERT(getType().getBasicType() == EbtFloat);
2378 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302379 float length = VectorLength(operandArray, objectSize);
2380 if (length)
2381 resultArray[i].setFConst(x / length);
2382 else
Olli Etuahof119a262016-08-19 15:54:22 +03002383 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2384 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302385 break;
2386 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002387 case EOpBitfieldReverse:
2388 {
2389 uint32_t value;
2390 if (getType().getBasicType() == EbtInt)
2391 {
2392 value = static_cast<uint32_t>(operandArray[i].getIConst());
2393 }
2394 else
2395 {
2396 ASSERT(getType().getBasicType() == EbtUInt);
2397 value = operandArray[i].getUConst();
2398 }
2399 uint32_t result = gl::BitfieldReverse(value);
2400 if (getType().getBasicType() == EbtInt)
2401 {
2402 resultArray[i].setIConst(static_cast<int32_t>(result));
2403 }
2404 else
2405 {
2406 resultArray[i].setUConst(result);
2407 }
2408 break;
2409 }
2410 case EOpBitCount:
2411 {
2412 uint32_t value;
2413 if (getType().getBasicType() == EbtInt)
2414 {
2415 value = static_cast<uint32_t>(operandArray[i].getIConst());
2416 }
2417 else
2418 {
2419 ASSERT(getType().getBasicType() == EbtUInt);
2420 value = operandArray[i].getUConst();
2421 }
2422 int result = gl::BitCount(value);
2423 resultArray[i].setIConst(result);
2424 break;
2425 }
2426 case EOpFindLSB:
2427 {
2428 uint32_t value;
2429 if (getType().getBasicType() == EbtInt)
2430 {
2431 value = static_cast<uint32_t>(operandArray[i].getIConst());
2432 }
2433 else
2434 {
2435 ASSERT(getType().getBasicType() == EbtUInt);
2436 value = operandArray[i].getUConst();
2437 }
2438 resultArray[i].setIConst(gl::FindLSB(value));
2439 break;
2440 }
2441 case EOpFindMSB:
2442 {
2443 uint32_t value;
2444 if (getType().getBasicType() == EbtInt)
2445 {
2446 int intValue = operandArray[i].getIConst();
2447 value = static_cast<uint32_t>(intValue);
2448 if (intValue < 0)
2449 {
2450 // Look for zero instead of one in value. This also handles the intValue ==
2451 // -1 special case, where the return value needs to be -1.
2452 value = ~value;
2453 }
2454 }
2455 else
2456 {
2457 ASSERT(getType().getBasicType() == EbtUInt);
2458 value = operandArray[i].getUConst();
2459 }
2460 resultArray[i].setIConst(gl::FindMSB(value));
2461 break;
2462 }
Olli Etuahof119a262016-08-19 15:54:22 +03002463 case EOpDFdx:
2464 case EOpDFdy:
2465 case EOpFwidth:
2466 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302467 // Derivatives of constant arguments should be 0.
2468 resultArray[i].setFConst(0.0f);
2469 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302470
Olli Etuahof119a262016-08-19 15:54:22 +03002471 default:
2472 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302473 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302474 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002475
Arun Patoleab2b9a22015-07-06 18:27:56 +05302476 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002477}
2478
Olli Etuahof119a262016-08-19 15:54:22 +03002479void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2480 FloatTypeUnaryFunc builtinFunc,
2481 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302482{
2483 ASSERT(builtinFunc);
2484
Olli Etuahof119a262016-08-19 15:54:22 +03002485 ASSERT(getType().getBasicType() == EbtFloat);
2486 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302487}
2488
Jamie Madillb1a85f42014-08-19 15:23:24 -04002489// static
Olli Etuahof119a262016-08-19 15:54:22 +03002490TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002491{
2492 ASSERT(aggregate->getSequence()->size() > 0u);
2493 size_t resultSize = aggregate->getType().getObjectSize();
2494 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2495 TBasicType basicType = aggregate->getBasicType();
2496
2497 size_t resultIndex = 0u;
2498
2499 if (aggregate->getSequence()->size() == 1u)
2500 {
2501 TIntermNode *argument = aggregate->getSequence()->front();
2502 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2503 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2504 // Check the special case of constructing a matrix diagonal from a single scalar,
2505 // or a vector from a single scalar.
2506 if (argumentConstant->getType().getObjectSize() == 1u)
2507 {
2508 if (aggregate->isMatrix())
2509 {
2510 int resultCols = aggregate->getType().getCols();
2511 int resultRows = aggregate->getType().getRows();
2512 for (int col = 0; col < resultCols; ++col)
2513 {
2514 for (int row = 0; row < resultRows; ++row)
2515 {
2516 if (col == row)
2517 {
2518 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2519 }
2520 else
2521 {
2522 resultArray[resultIndex].setFConst(0.0f);
2523 }
2524 ++resultIndex;
2525 }
2526 }
2527 }
2528 else
2529 {
2530 while (resultIndex < resultSize)
2531 {
2532 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2533 ++resultIndex;
2534 }
2535 }
2536 ASSERT(resultIndex == resultSize);
2537 return resultArray;
2538 }
2539 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2540 {
2541 // The special case of constructing a matrix from a matrix.
2542 int argumentCols = argumentConstant->getType().getCols();
2543 int argumentRows = argumentConstant->getType().getRows();
2544 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002545 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002546 for (int col = 0; col < resultCols; ++col)
2547 {
2548 for (int row = 0; row < resultRows; ++row)
2549 {
2550 if (col < argumentCols && row < argumentRows)
2551 {
2552 resultArray[resultIndex].cast(basicType,
2553 argumentUnionArray[col * argumentRows + row]);
2554 }
2555 else if (col == row)
2556 {
2557 resultArray[resultIndex].setFConst(1.0f);
2558 }
2559 else
2560 {
2561 resultArray[resultIndex].setFConst(0.0f);
2562 }
2563 ++resultIndex;
2564 }
2565 }
2566 ASSERT(resultIndex == resultSize);
2567 return resultArray;
2568 }
2569 }
2570
2571 for (TIntermNode *&argument : *aggregate->getSequence())
2572 {
2573 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2574 size_t argumentSize = argumentConstant->getType().getObjectSize();
2575 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2576 for (size_t i = 0u; i < argumentSize; ++i)
2577 {
2578 if (resultIndex >= resultSize)
2579 break;
2580 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2581 ++resultIndex;
2582 }
2583 }
2584 ASSERT(resultIndex == resultSize);
2585 return resultArray;
2586}
2587
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002588bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2589{
2590 switch (op)
2591 {
2592 case EOpAtan:
2593 case EOpPow:
2594 case EOpMod:
2595 case EOpMin:
2596 case EOpMax:
2597 case EOpClamp:
2598 case EOpMix:
2599 case EOpStep:
2600 case EOpSmoothStep:
2601 case EOpLdexp:
2602 case EOpMulMatrixComponentWise:
2603 case EOpOuterProduct:
2604 case EOpEqualComponentWise:
2605 case EOpNotEqualComponentWise:
2606 case EOpLessThanComponentWise:
2607 case EOpLessThanEqualComponentWise:
2608 case EOpGreaterThanComponentWise:
2609 case EOpGreaterThanEqualComponentWise:
2610 case EOpDistance:
2611 case EOpDot:
2612 case EOpCross:
2613 case EOpFaceforward:
2614 case EOpReflect:
2615 case EOpRefract:
2616 case EOpBitfieldExtract:
2617 case EOpBitfieldInsert:
2618 return true;
2619 default:
2620 return false;
2621 }
2622}
2623
Olli Etuaho1d122782015-11-06 15:35:17 +02002624// static
Olli Etuahof119a262016-08-19 15:54:22 +03002625TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2626 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302627{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002628 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002629 TIntermSequence *arguments = aggregate->getSequence();
2630 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2631 std::vector<const TConstantUnion *> unionArrays(argsCount);
2632 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002633 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302634 TBasicType basicType = EbtVoid;
2635 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002636 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302637 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002638 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2639 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302640
2641 if (i == 0)
2642 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002643 basicType = argConstant->getType().getBasicType();
2644 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302645 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002646 unionArrays[i] = argConstant->getUnionArrayPointer();
2647 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002648 if (objectSizes[i] > maxObjectSize)
2649 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302650 }
2651
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002652 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302653 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002654 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302655 if (objectSizes[i] != maxObjectSize)
2656 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2657 }
Arun Patole274f0702015-05-05 13:33:30 +05302658
Olli Etuahob43846e2015-06-02 18:18:57 +03002659 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002660
2661 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302662 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002663 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302664 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002665 ASSERT(basicType == EbtFloat);
2666 resultArray = new TConstantUnion[maxObjectSize];
2667 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302668 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002669 float y = unionArrays[0][i].getFConst();
2670 float x = unionArrays[1][i].getFConst();
2671 // Results are undefined if x and y are both 0.
2672 if (x == 0.0f && y == 0.0f)
2673 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2674 else
2675 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302676 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002677 break;
2678 }
Arun Patolebf790422015-05-18 17:53:04 +05302679
Olli Etuaho51182ab2017-01-22 00:12:29 +00002680 case EOpPow:
2681 {
2682 ASSERT(basicType == EbtFloat);
2683 resultArray = new TConstantUnion[maxObjectSize];
2684 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302685 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002686 float x = unionArrays[0][i].getFConst();
2687 float y = unionArrays[1][i].getFConst();
2688 // Results are undefined if x < 0.
2689 // Results are undefined if x = 0 and y <= 0.
2690 if (x < 0.0f)
2691 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2692 else if (x == 0.0f && y <= 0.0f)
2693 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2694 else
2695 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302696 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002697 break;
2698 }
Arun Patolebf790422015-05-18 17:53:04 +05302699
Olli Etuaho51182ab2017-01-22 00:12:29 +00002700 case EOpMod:
2701 {
2702 ASSERT(basicType == EbtFloat);
2703 resultArray = new TConstantUnion[maxObjectSize];
2704 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302705 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002706 float x = unionArrays[0][i].getFConst();
2707 float y = unionArrays[1][i].getFConst();
2708 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302709 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002710 break;
2711 }
Arun Patolebf790422015-05-18 17:53:04 +05302712
Olli Etuaho51182ab2017-01-22 00:12:29 +00002713 case EOpMin:
2714 {
2715 resultArray = new TConstantUnion[maxObjectSize];
2716 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302717 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002718 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302719 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002720 case EbtFloat:
2721 resultArray[i].setFConst(
2722 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2723 break;
2724 case EbtInt:
2725 resultArray[i].setIConst(
2726 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2727 break;
2728 case EbtUInt:
2729 resultArray[i].setUConst(
2730 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2731 break;
2732 default:
2733 UNREACHABLE();
2734 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302735 }
2736 }
2737 break;
Arun Patole274f0702015-05-05 13:33:30 +05302738 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002739
2740 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302741 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002742 resultArray = new TConstantUnion[maxObjectSize];
2743 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302744 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002745 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302746 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002747 case EbtFloat:
2748 resultArray[i].setFConst(
2749 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2750 break;
2751 case EbtInt:
2752 resultArray[i].setIConst(
2753 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2754 break;
2755 case EbtUInt:
2756 resultArray[i].setUConst(
2757 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2758 break;
2759 default:
2760 UNREACHABLE();
2761 break;
Arun Patole274f0702015-05-05 13:33:30 +05302762 }
2763 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002764 break;
Arun Patole274f0702015-05-05 13:33:30 +05302765 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002766
2767 case EOpStep:
2768 {
2769 ASSERT(basicType == EbtFloat);
2770 resultArray = new TConstantUnion[maxObjectSize];
2771 for (size_t i = 0; i < maxObjectSize; i++)
2772 resultArray[i].setFConst(
2773 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2774 break;
2775 }
2776
2777 case EOpLessThanComponentWise:
2778 {
2779 resultArray = new TConstantUnion[maxObjectSize];
2780 for (size_t i = 0; i < maxObjectSize; i++)
2781 {
2782 switch (basicType)
2783 {
2784 case EbtFloat:
2785 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2786 unionArrays[1][i].getFConst());
2787 break;
2788 case EbtInt:
2789 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2790 unionArrays[1][i].getIConst());
2791 break;
2792 case EbtUInt:
2793 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2794 unionArrays[1][i].getUConst());
2795 break;
2796 default:
2797 UNREACHABLE();
2798 break;
2799 }
2800 }
2801 break;
2802 }
2803
2804 case EOpLessThanEqualComponentWise:
2805 {
2806 resultArray = new TConstantUnion[maxObjectSize];
2807 for (size_t i = 0; i < maxObjectSize; i++)
2808 {
2809 switch (basicType)
2810 {
2811 case EbtFloat:
2812 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2813 unionArrays[1][i].getFConst());
2814 break;
2815 case EbtInt:
2816 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2817 unionArrays[1][i].getIConst());
2818 break;
2819 case EbtUInt:
2820 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2821 unionArrays[1][i].getUConst());
2822 break;
2823 default:
2824 UNREACHABLE();
2825 break;
2826 }
2827 }
2828 break;
2829 }
2830
2831 case EOpGreaterThanComponentWise:
2832 {
2833 resultArray = new TConstantUnion[maxObjectSize];
2834 for (size_t i = 0; i < maxObjectSize; i++)
2835 {
2836 switch (basicType)
2837 {
2838 case EbtFloat:
2839 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2840 unionArrays[1][i].getFConst());
2841 break;
2842 case EbtInt:
2843 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2844 unionArrays[1][i].getIConst());
2845 break;
2846 case EbtUInt:
2847 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2848 unionArrays[1][i].getUConst());
2849 break;
2850 default:
2851 UNREACHABLE();
2852 break;
2853 }
2854 }
2855 break;
2856 }
2857 case EOpGreaterThanEqualComponentWise:
2858 {
2859 resultArray = new TConstantUnion[maxObjectSize];
2860 for (size_t i = 0; i < maxObjectSize; i++)
2861 {
2862 switch (basicType)
2863 {
2864 case EbtFloat:
2865 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2866 unionArrays[1][i].getFConst());
2867 break;
2868 case EbtInt:
2869 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2870 unionArrays[1][i].getIConst());
2871 break;
2872 case EbtUInt:
2873 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2874 unionArrays[1][i].getUConst());
2875 break;
2876 default:
2877 UNREACHABLE();
2878 break;
2879 }
2880 }
2881 }
2882 break;
2883
2884 case EOpEqualComponentWise:
2885 {
2886 resultArray = new TConstantUnion[maxObjectSize];
2887 for (size_t i = 0; i < maxObjectSize; i++)
2888 {
2889 switch (basicType)
2890 {
2891 case EbtFloat:
2892 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2893 unionArrays[1][i].getFConst());
2894 break;
2895 case EbtInt:
2896 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2897 unionArrays[1][i].getIConst());
2898 break;
2899 case EbtUInt:
2900 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2901 unionArrays[1][i].getUConst());
2902 break;
2903 case EbtBool:
2904 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2905 unionArrays[1][i].getBConst());
2906 break;
2907 default:
2908 UNREACHABLE();
2909 break;
2910 }
2911 }
2912 break;
2913 }
2914
2915 case EOpNotEqualComponentWise:
2916 {
2917 resultArray = new TConstantUnion[maxObjectSize];
2918 for (size_t i = 0; i < maxObjectSize; i++)
2919 {
2920 switch (basicType)
2921 {
2922 case EbtFloat:
2923 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2924 unionArrays[1][i].getFConst());
2925 break;
2926 case EbtInt:
2927 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2928 unionArrays[1][i].getIConst());
2929 break;
2930 case EbtUInt:
2931 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2932 unionArrays[1][i].getUConst());
2933 break;
2934 case EbtBool:
2935 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2936 unionArrays[1][i].getBConst());
2937 break;
2938 default:
2939 UNREACHABLE();
2940 break;
2941 }
2942 }
2943 break;
2944 }
2945
2946 case EOpDistance:
2947 {
2948 ASSERT(basicType == EbtFloat);
2949 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2950 resultArray = new TConstantUnion();
2951 for (size_t i = 0; i < maxObjectSize; i++)
2952 {
2953 float x = unionArrays[0][i].getFConst();
2954 float y = unionArrays[1][i].getFConst();
2955 distanceArray[i].setFConst(x - y);
2956 }
2957 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2958 break;
2959 }
2960
2961 case EOpDot:
2962 ASSERT(basicType == EbtFloat);
2963 resultArray = new TConstantUnion();
2964 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2965 break;
2966
2967 case EOpCross:
2968 {
2969 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2970 resultArray = new TConstantUnion[maxObjectSize];
2971 float x0 = unionArrays[0][0].getFConst();
2972 float x1 = unionArrays[0][1].getFConst();
2973 float x2 = unionArrays[0][2].getFConst();
2974 float y0 = unionArrays[1][0].getFConst();
2975 float y1 = unionArrays[1][1].getFConst();
2976 float y2 = unionArrays[1][2].getFConst();
2977 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2978 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2979 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2980 break;
2981 }
2982
2983 case EOpReflect:
2984 {
2985 ASSERT(basicType == EbtFloat);
2986 // genType reflect (genType I, genType N) :
2987 // For the incident vector I and surface orientation N, returns the reflection
2988 // direction:
2989 // I - 2 * dot(N, I) * N.
2990 resultArray = new TConstantUnion[maxObjectSize];
2991 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2992 for (size_t i = 0; i < maxObjectSize; i++)
2993 {
2994 float result = unionArrays[0][i].getFConst() -
2995 2.0f * dotProduct * unionArrays[1][i].getFConst();
2996 resultArray[i].setFConst(result);
2997 }
2998 break;
2999 }
3000
3001 case EOpMulMatrixComponentWise:
3002 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003003 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3004 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003005 // Perform component-wise matrix multiplication.
3006 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003007 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003008 angle::Matrix<float> result =
3009 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3010 SetUnionArrayFromMatrix(result, resultArray);
3011 break;
3012 }
3013
3014 case EOpOuterProduct:
3015 {
3016 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003017 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3018 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003019 resultArray = new TConstantUnion[numRows * numCols];
3020 angle::Matrix<float> result =
3021 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3022 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3023 SetUnionArrayFromMatrix(result, resultArray);
3024 break;
3025 }
3026
3027 case EOpClamp:
3028 {
3029 resultArray = new TConstantUnion[maxObjectSize];
3030 for (size_t i = 0; i < maxObjectSize; i++)
3031 {
3032 switch (basicType)
3033 {
3034 case EbtFloat:
3035 {
3036 float x = unionArrays[0][i].getFConst();
3037 float min = unionArrays[1][i].getFConst();
3038 float max = unionArrays[2][i].getFConst();
3039 // Results are undefined if min > max.
3040 if (min > max)
3041 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3042 &resultArray[i]);
3043 else
3044 resultArray[i].setFConst(gl::clamp(x, min, max));
3045 break;
3046 }
3047
3048 case EbtInt:
3049 {
3050 int x = unionArrays[0][i].getIConst();
3051 int min = unionArrays[1][i].getIConst();
3052 int max = unionArrays[2][i].getIConst();
3053 // Results are undefined if min > max.
3054 if (min > max)
3055 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3056 &resultArray[i]);
3057 else
3058 resultArray[i].setIConst(gl::clamp(x, min, max));
3059 break;
3060 }
3061 case EbtUInt:
3062 {
3063 unsigned int x = unionArrays[0][i].getUConst();
3064 unsigned int min = unionArrays[1][i].getUConst();
3065 unsigned int max = unionArrays[2][i].getUConst();
3066 // Results are undefined if min > max.
3067 if (min > max)
3068 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3069 &resultArray[i]);
3070 else
3071 resultArray[i].setUConst(gl::clamp(x, min, max));
3072 break;
3073 }
3074 default:
3075 UNREACHABLE();
3076 break;
3077 }
3078 }
3079 break;
3080 }
3081
3082 case EOpMix:
3083 {
3084 ASSERT(basicType == EbtFloat);
3085 resultArray = new TConstantUnion[maxObjectSize];
3086 for (size_t i = 0; i < maxObjectSize; i++)
3087 {
3088 float x = unionArrays[0][i].getFConst();
3089 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003090 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003091 if (type == EbtFloat)
3092 {
3093 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3094 float a = unionArrays[2][i].getFConst();
3095 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3096 }
3097 else // 3rd parameter is EbtBool
3098 {
3099 ASSERT(type == EbtBool);
3100 // Selects which vector each returned component comes from.
3101 // For a component of a that is false, the corresponding component of x is
3102 // returned.
3103 // For a component of a that is true, the corresponding component of y is
3104 // returned.
3105 bool a = unionArrays[2][i].getBConst();
3106 resultArray[i].setFConst(a ? y : x);
3107 }
3108 }
3109 break;
3110 }
3111
3112 case EOpSmoothStep:
3113 {
3114 ASSERT(basicType == EbtFloat);
3115 resultArray = new TConstantUnion[maxObjectSize];
3116 for (size_t i = 0; i < maxObjectSize; i++)
3117 {
3118 float edge0 = unionArrays[0][i].getFConst();
3119 float edge1 = unionArrays[1][i].getFConst();
3120 float x = unionArrays[2][i].getFConst();
3121 // Results are undefined if edge0 >= edge1.
3122 if (edge0 >= edge1)
3123 {
3124 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3125 }
3126 else
3127 {
3128 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3129 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3130 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3131 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3132 }
3133 }
3134 break;
3135 }
3136
Olli Etuaho74da73f2017-02-01 15:37:48 +00003137 case EOpLdexp:
3138 {
3139 resultArray = new TConstantUnion[maxObjectSize];
3140 for (size_t i = 0; i < maxObjectSize; i++)
3141 {
3142 float x = unionArrays[0][i].getFConst();
3143 int exp = unionArrays[1][i].getIConst();
3144 if (exp > 128)
3145 {
3146 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3147 }
3148 else
3149 {
3150 resultArray[i].setFConst(gl::Ldexp(x, exp));
3151 }
3152 }
3153 break;
3154 }
3155
Jamie Madille72595b2017-06-06 15:12:26 -04003156 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003157 {
3158 ASSERT(basicType == EbtFloat);
3159 // genType faceforward(genType N, genType I, genType Nref) :
3160 // If dot(Nref, I) < 0 return N, otherwise return -N.
3161 resultArray = new TConstantUnion[maxObjectSize];
3162 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3163 for (size_t i = 0; i < maxObjectSize; i++)
3164 {
3165 if (dotProduct < 0)
3166 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3167 else
3168 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3169 }
3170 break;
3171 }
3172
3173 case EOpRefract:
3174 {
3175 ASSERT(basicType == EbtFloat);
3176 // genType refract(genType I, genType N, float eta) :
3177 // For the incident vector I and surface normal N, and the ratio of indices of
3178 // refraction eta,
3179 // return the refraction vector. The result is computed by
3180 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3181 // if (k < 0.0)
3182 // return genType(0.0)
3183 // else
3184 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3185 resultArray = new TConstantUnion[maxObjectSize];
3186 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3187 for (size_t i = 0; i < maxObjectSize; i++)
3188 {
3189 float eta = unionArrays[2][i].getFConst();
3190 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3191 if (k < 0.0f)
3192 resultArray[i].setFConst(0.0f);
3193 else
3194 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3195 (eta * dotProduct + sqrtf(k)) *
3196 unionArrays[1][i].getFConst());
3197 }
3198 break;
3199 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003200 case EOpBitfieldExtract:
3201 {
3202 resultArray = new TConstantUnion[maxObjectSize];
3203 for (size_t i = 0; i < maxObjectSize; ++i)
3204 {
3205 int offset = unionArrays[1][0].getIConst();
3206 int bits = unionArrays[2][0].getIConst();
3207 if (bits == 0)
3208 {
3209 if (aggregate->getBasicType() == EbtInt)
3210 {
3211 resultArray[i].setIConst(0);
3212 }
3213 else
3214 {
3215 ASSERT(aggregate->getBasicType() == EbtUInt);
3216 resultArray[i].setUConst(0);
3217 }
3218 }
3219 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3220 {
3221 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3222 &resultArray[i]);
3223 }
3224 else
3225 {
3226 // bits can be 32 here, so we need to avoid bit shift overflow.
3227 uint32_t maskMsb = 1u << (bits - 1);
3228 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3229 if (aggregate->getBasicType() == EbtInt)
3230 {
3231 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3232 uint32_t resultUnsigned = (value & mask) >> offset;
3233 if ((resultUnsigned & maskMsb) != 0)
3234 {
3235 // The most significant bits (from bits+1 to the most significant bit)
3236 // should be set to 1.
3237 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3238 resultUnsigned |= higherBitsMask;
3239 }
3240 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3241 }
3242 else
3243 {
3244 ASSERT(aggregate->getBasicType() == EbtUInt);
3245 uint32_t value = unionArrays[0][i].getUConst();
3246 resultArray[i].setUConst((value & mask) >> offset);
3247 }
3248 }
3249 }
3250 break;
3251 }
3252 case EOpBitfieldInsert:
3253 {
3254 resultArray = new TConstantUnion[maxObjectSize];
3255 for (size_t i = 0; i < maxObjectSize; ++i)
3256 {
3257 int offset = unionArrays[2][0].getIConst();
3258 int bits = unionArrays[3][0].getIConst();
3259 if (bits == 0)
3260 {
3261 if (aggregate->getBasicType() == EbtInt)
3262 {
3263 int32_t base = unionArrays[0][i].getIConst();
3264 resultArray[i].setIConst(base);
3265 }
3266 else
3267 {
3268 ASSERT(aggregate->getBasicType() == EbtUInt);
3269 uint32_t base = unionArrays[0][i].getUConst();
3270 resultArray[i].setUConst(base);
3271 }
3272 }
3273 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3274 {
3275 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3276 &resultArray[i]);
3277 }
3278 else
3279 {
3280 // bits can be 32 here, so we need to avoid bit shift overflow.
3281 uint32_t maskMsb = 1u << (bits - 1);
3282 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3283 uint32_t baseMask = ~insertMask;
3284 if (aggregate->getBasicType() == EbtInt)
3285 {
3286 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3287 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3288 uint32_t resultUnsigned =
3289 (base & baseMask) | ((insert << offset) & insertMask);
3290 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3291 }
3292 else
3293 {
3294 ASSERT(aggregate->getBasicType() == EbtUInt);
3295 uint32_t base = unionArrays[0][i].getUConst();
3296 uint32_t insert = unionArrays[1][i].getUConst();
3297 resultArray[i].setUConst((base & baseMask) |
3298 ((insert << offset) & insertMask));
3299 }
3300 }
3301 }
3302 break;
3303 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003304
3305 default:
3306 UNREACHABLE();
3307 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303308 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003309 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303310}
3311
Jamie Madill45bcc782016-11-07 13:58:48 -05003312} // namespace sh