blob: b68724c3b3e21815e7b2a50cb76948f4bce18324 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040021#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040023#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040024
Jamie Madill45bcc782016-11-07 13:58:48 -050025namespace sh
26{
27
Jamie Madillb1a85f42014-08-19 15:23:24 -040028namespace
29{
30
Jamie Madilld7b1ab52016-12-12 14:42:19 -050031const float kPi = 3.14159265358979323846f;
Arun Patole9dea48f2015-04-02 11:45:09 +053032const float kDegreesToRadiansMultiplier = kPi / 180.0f;
33const float kRadiansToDegreesMultiplier = 180.0f / kPi;
34
Jamie Madillb1a85f42014-08-19 15:23:24 -040035TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
36{
37 return left > right ? left : right;
38}
39
Arun Patole274f0702015-05-05 13:33:30 +053040TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
41{
42 TConstantUnion *constUnion = new TConstantUnion[size];
43 for (unsigned int i = 0; i < size; ++i)
Jamie Madilld7b1ab52016-12-12 14:42:19 -050044 constUnion[i] = constant;
Arun Patole274f0702015-05-05 13:33:30 +053045
46 return constUnion;
47}
48
Olli Etuahof119a262016-08-19 15:54:22 +030049void UndefinedConstantFoldingError(const TSourceLoc &loc,
50 TOperator op,
51 TBasicType basicType,
52 TDiagnostics *diagnostics,
53 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053054{
Olli Etuahof119a262016-08-19 15:54:22 +030055 diagnostics->warning(loc, "operation result is undefined for the values passed in",
Olli Etuaho4de340a2016-12-16 09:32:03 +000056 GetOperatorString(op));
Arun Patolebf790422015-05-18 17:53:04 +053057
58 switch (basicType)
59 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050060 case EbtFloat:
61 result->setFConst(0.0f);
62 break;
63 case EbtInt:
64 result->setIConst(0);
65 break;
66 case EbtUInt:
67 result->setUConst(0u);
68 break;
69 case EbtBool:
70 result->setBConst(false);
71 break;
72 default:
73 break;
Arun Patolebf790422015-05-18 17:53:04 +053074 }
75}
76
Olli Etuaho5c0e0232015-11-11 15:55:59 +020077float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053078{
79 float result = 0.0f;
80 for (size_t i = 0; i < paramArraySize; i++)
81 {
82 float f = paramArray[i].getFConst();
83 result += f * f;
84 }
85 return sqrtf(result);
86}
87
Olli Etuaho5c0e0232015-11-11 15:55:59 +020088float VectorDotProduct(const TConstantUnion *paramArray1,
89 const TConstantUnion *paramArray2,
90 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053091{
92 float result = 0.0f;
93 for (size_t i = 0; i < paramArraySize; i++)
94 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
95 return result;
96}
97
Olli Etuaho3272a6d2016-08-29 17:54:50 +030098TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
Olli Etuaho7c3848e2015-11-04 13:19:17 +020099 const TIntermTyped *originalNode,
100 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300101{
102 if (constArray == nullptr)
103 {
104 return nullptr;
105 }
106 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200107 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300108 folded->setLine(originalNode->getLine());
109 return folded;
110}
111
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200112angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
113 const unsigned int &rows,
114 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530115{
116 std::vector<float> elements;
117 for (size_t i = 0; i < rows * cols; i++)
118 elements.push_back(paramArray[i].getFConst());
119 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300120 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
121 // so that the created matrix will have the expected dimensions after the transpose.
122 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530123}
124
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200125angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530126{
127 std::vector<float> elements;
128 for (size_t i = 0; i < size * size; i++)
129 elements.push_back(paramArray[i].getFConst());
130 // Transpose is used since the Matrix constructor expects arguments in row-major order,
131 // whereas the paramArray is in column-major order.
132 return angle::Matrix<float>(elements, size).transpose();
133}
134
135void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
136{
137 // Transpose is used since the input Matrix is in row-major order,
138 // whereas the actual result should be in column-major order.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500139 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530140 std::vector<float> resultElements = result.elements();
141 for (size_t i = 0; i < resultElements.size(); i++)
142 resultArray[i].setFConst(resultElements[i]);
143}
144
Jamie Madillb1a85f42014-08-19 15:23:24 -0400145} // namespace anonymous
146
Olli Etuahoae4dbf32017-12-08 20:49:00 +0100147TName::TName(const TString *name) : mName(name ? (*name) : ""), mIsInternal(false)
148{
149}
150
Jamie Madillb1a85f42014-08-19 15:23:24 -0400151////////////////////////////////////////////////////////////////
152//
153// Member functions of the nodes used for building the tree.
154//
155////////////////////////////////////////////////////////////////
156
Olli Etuahod2a67b92014-10-21 16:42:57 +0300157void TIntermTyped::setTypePreservePrecision(const TType &t)
158{
159 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500160 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300161 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
162 mType.setPrecision(precision);
163}
164
Jamie Madillb1a85f42014-08-19 15:23:24 -0400165#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500166 if (node == original) \
167 { \
168 node = static_cast<type *>(replacement); \
169 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400170 }
171
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500172bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400173{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300174 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400175 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
176 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
177 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100178 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400179 return false;
180}
181
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500182bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400183{
184 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
185 return false;
186}
187
Olli Etuahob6fa0432016-09-28 16:28:05 +0100188bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
189{
190 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
191 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
192 return false;
193}
194
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500195bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400196{
197 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
198 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
199 return false;
200}
201
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500202bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400203{
Olli Etuahoa2234302016-08-31 12:05:39 +0300204 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400205 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
206 return false;
207}
208
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000209bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
210{
211 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
212 return false;
213}
214
Olli Etuaho336b1472016-10-05 16:37:55 +0100215bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
216{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000217 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100218 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
219 return false;
220}
221
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500222bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400223{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100224 return replaceChildNodeInternal(original, replacement);
225}
226
227bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
228{
229 return replaceChildNodeInternal(original, replacement);
230}
231
Olli Etuaho16c745a2017-01-16 17:02:27 +0000232bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
233{
234 return replaceChildNodeInternal(original, replacement);
235}
236
Olli Etuaho13389b62016-10-16 11:48:18 +0100237bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
238{
239 return replaceChildNodeInternal(original, replacement);
240}
241
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100242bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
243{
244 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400245 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100246 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400247 }
248 return false;
249}
250
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100251bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
252 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300253{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100254 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300255 {
256 if (*it == original)
257 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100258 it = getSequence()->erase(it);
259 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300260 return true;
261 }
262 }
263 return false;
264}
265
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100266bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
267 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300268{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100269 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300270 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300271 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300272 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100273 auto it = getSequence()->begin() + position;
274 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300275 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300276}
277
Olli Etuaho195be942017-12-04 23:40:14 +0200278TIntermSymbol::TIntermSymbol(const TVariable *variable)
279 : TIntermTyped(variable->getType()), mId(variable->uniqueId()), mSymbol(variable->name())
280{
281 if (variable->symbolType() == SymbolType::AngleInternal)
282 {
283 mSymbol.setInternal(true);
284 }
285}
286
Olli Etuahofe486322017-03-21 09:30:54 +0000287TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
288 TIntermSequence *arguments)
289{
290 TIntermAggregate *callNode =
291 new TIntermAggregate(func.getReturnType(), EOpCallFunctionInAST, arguments);
292 callNode->getFunctionSymbolInfo()->setFromFunction(func);
293 return callNode;
294}
295
296TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TType &type,
297 const TSymbolUniqueId &id,
298 const TName &name,
299 TIntermSequence *arguments)
300{
301 TIntermAggregate *callNode = new TIntermAggregate(type, EOpCallFunctionInAST, arguments);
302 callNode->getFunctionSymbolInfo()->setId(id);
303 callNode->getFunctionSymbolInfo()->setNameObj(name);
304 return callNode;
305}
306
307TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
308 TIntermSequence *arguments)
309{
310 TIntermAggregate *callNode =
311 new TIntermAggregate(func.getReturnType(), EOpCallBuiltInFunction, arguments);
312 callNode->getFunctionSymbolInfo()->setFromFunction(func);
313 // Note that name needs to be set before texture function type is determined.
314 callNode->setBuiltInFunctionPrecision();
315 return callNode;
316}
317
318TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000319 TIntermSequence *arguments)
320{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300321 return new TIntermAggregate(type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000322}
323
324TIntermAggregate *TIntermAggregate::Create(const TType &type,
325 TOperator op,
326 TIntermSequence *arguments)
327{
328 TIntermAggregate *node = new TIntermAggregate(type, op, arguments);
329 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
330 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
331 ASSERT(!node->isConstructor()); // Should use CreateConstructor
332 return node;
333}
334
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800335TIntermAggregate::TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments)
336 : TIntermOperator(op), mUseEmulatedFunction(false), mGotPrecisionFromChildren(false)
337{
338 if (arguments != nullptr)
339 {
340 mArguments.swap(*arguments);
341 }
342 setTypePrecisionAndQualifier(type);
343}
344
345void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
346{
347 setType(type);
348 mType.setQualifier(EvqTemporary);
349 if (!isFunctionCall())
350 {
351 if (isConstructor())
352 {
353 // Structs should not be precision qualified, the individual members may be.
354 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300355 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800356 {
357 setPrecisionFromChildren();
358 }
359 }
360 else
361 {
362 setPrecisionForBuiltInOp();
363 }
364 if (areChildrenConstQualified())
365 {
366 mType.setQualifier(EvqConst);
367 }
368 }
369}
370
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200371bool TIntermAggregate::areChildrenConstQualified()
372{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800373 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200374 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800375 TIntermTyped *typedArg = arg->getAsTyped();
376 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200377 {
378 return false;
379 }
380 }
381 return true;
382}
383
Olli Etuahod2a67b92014-10-21 16:42:57 +0300384void TIntermAggregate::setPrecisionFromChildren()
385{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300386 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300387 if (getBasicType() == EbtBool)
388 {
389 mType.setPrecision(EbpUndefined);
390 return;
391 }
392
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500393 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800394 TIntermSequence::iterator childIter = mArguments.begin();
395 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300396 {
397 TIntermTyped *typed = (*childIter)->getAsTyped();
398 if (typed)
399 precision = GetHigherPrecision(typed->getPrecision(), precision);
400 ++childIter;
401 }
402 mType.setPrecision(precision);
403}
404
Olli Etuaho9250cb22017-01-21 10:51:27 +0000405void TIntermAggregate::setPrecisionForBuiltInOp()
406{
407 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800408 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000409 if (!setPrecisionForSpecialBuiltInOp())
410 {
411 setPrecisionFromChildren();
412 }
413}
414
415bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
416{
417 switch (mOp)
418 {
419 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800420 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
421 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000422 return true;
423 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800424 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
425 mArguments[1]->getAsTyped()->getPrecision()));
426 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000427 return true;
428 case EOpUaddCarry:
429 case EOpUsubBorrow:
430 mType.setPrecision(EbpHigh);
431 return true;
432 default:
433 return false;
434 }
435}
436
Olli Etuahod2a67b92014-10-21 16:42:57 +0300437void TIntermAggregate::setBuiltInFunctionPrecision()
438{
439 // All built-ins returning bool should be handled as ops, not functions.
440 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800441 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300442
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800443 TPrecision precision = EbpUndefined;
444 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300445 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800446 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300447 // ESSL spec section 8: texture functions get their precision from the sampler.
448 if (typed && IsSampler(typed->getBasicType()))
449 {
450 precision = typed->getPrecision();
451 break;
452 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300453 }
454 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
455 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobd674552016-10-06 13:28:42 +0100456 if (mFunctionInfo.getName().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300457 mType.setPrecision(EbpHigh);
458 else
459 mType.setPrecision(precision);
460}
461
Olli Etuahof2209f72017-04-01 12:45:55 +0300462TString TIntermAggregate::getSymbolTableMangledName() const
463{
464 ASSERT(!isConstructor());
465 switch (mOp)
466 {
467 case EOpCallInternalRawFunction:
468 case EOpCallBuiltInFunction:
469 case EOpCallFunctionInAST:
470 return TFunction::GetMangledNameFromCall(mFunctionInfo.getName(), mArguments);
471 default:
472 TString opString = GetOperatorString(mOp);
473 return TFunction::GetMangledNameFromCall(opString, mArguments);
474 }
475}
476
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300477bool TIntermAggregate::hasSideEffects() const
478{
479 if (isFunctionCall() && mFunctionInfo.isKnownToNotHaveSideEffects())
480 {
481 for (TIntermNode *arg : mArguments)
482 {
483 if (arg->getAsTyped()->hasSideEffects())
484 {
485 return true;
486 }
487 }
488 return false;
489 }
490 // Conservatively assume most aggregate operators have side-effects
491 return true;
492}
493
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100494void TIntermBlock::appendStatement(TIntermNode *statement)
495{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300496 // Declaration nodes with no children can appear if it was an empty declaration or if all the
497 // declarators just added constants to the symbol table instead of generating code. We still
498 // need to add the declaration to the AST in that case because it might be relevant to the
499 // validity of switch/case.
500 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100501 {
502 mStatements.push_back(statement);
503 }
504}
505
Olli Etuaho16c745a2017-01-16 17:02:27 +0000506void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
507{
508 ASSERT(parameter != nullptr);
509 mParameters.push_back(parameter);
510}
511
Olli Etuaho13389b62016-10-16 11:48:18 +0100512void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
513{
514 ASSERT(declarator != nullptr);
515 ASSERT(declarator->getAsSymbolNode() != nullptr ||
516 (declarator->getAsBinaryNode() != nullptr &&
517 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
518 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300519 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100520 mDeclarators.push_back(declarator);
521}
522
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300523bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
524{
525 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
526 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
527 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
528 return false;
529}
530
Olli Etuaho57961272016-09-14 13:57:46 +0300531bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400532{
533 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100534 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
535 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400536 return false;
537}
538
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500539bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200540{
541 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100542 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300543 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200544 return false;
545}
546
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500547bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200548{
549 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
550 return false;
551}
552
Olli Etuahod7a25242015-08-18 13:49:45 +0300553TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
554{
555 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
556 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
557 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
558 mLine = node.mLine;
559}
560
Olli Etuahod4f4c112016-04-15 15:11:24 +0300561bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
562{
563 TIntermAggregate *constructor = getAsAggregate();
564 if (!constructor || !constructor->isConstructor())
565 {
566 return false;
567 }
568 for (TIntermNode *&node : *constructor->getSequence())
569 {
570 if (!node->getAsConstantUnion())
571 return false;
572 }
573 return true;
574}
575
Olli Etuahod7a25242015-08-18 13:49:45 +0300576TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
577{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200578 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300579}
580
Olli Etuahobd674552016-10-06 13:28:42 +0100581void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
582{
Olli Etuahoae4dbf32017-12-08 20:49:00 +0100583 setName(*function.name());
Olli Etuahofe486322017-03-21 09:30:54 +0000584 setId(TSymbolUniqueId(function));
585}
586
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300587TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id)
588 : mId(new TSymbolUniqueId(id)), mKnownToNotHaveSideEffects(false)
Olli Etuahofe486322017-03-21 09:30:54 +0000589{
590}
591
592TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300593 : mName(info.mName), mId(nullptr), mKnownToNotHaveSideEffects(info.mKnownToNotHaveSideEffects)
Olli Etuahofe486322017-03-21 09:30:54 +0000594{
595 if (info.mId)
596 {
597 mId = new TSymbolUniqueId(*info.mId);
598 }
599}
600
601TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
602{
603 mName = info.mName;
604 if (info.mId)
605 {
606 mId = new TSymbolUniqueId(*info.mId);
607 }
608 else
609 {
610 mId = nullptr;
611 }
612 return *this;
613}
614
615void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
616{
617 mId = new TSymbolUniqueId(id);
618}
619
620const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
621{
622 ASSERT(mId);
623 return *mId;
Olli Etuahobd674552016-10-06 13:28:42 +0100624}
625
Olli Etuahod7a25242015-08-18 13:49:45 +0300626TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
627 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300628 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100629 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
630 mFunctionInfo(node.mFunctionInfo)
Olli Etuahod7a25242015-08-18 13:49:45 +0300631{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800632 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300633 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800634 TIntermTyped *typedArg = arg->getAsTyped();
635 ASSERT(typedArg != nullptr);
636 TIntermTyped *argCopy = typedArg->deepCopy();
637 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300638 }
639}
640
Olli Etuahofe486322017-03-21 09:30:54 +0000641TIntermAggregate *TIntermAggregate::shallowCopy() const
642{
643 TIntermSequence *copySeq = new TIntermSequence();
644 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
645 TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq);
646 *copyNode->getFunctionSymbolInfo() = mFunctionInfo;
647 copyNode->setLine(mLine);
648 return copyNode;
649}
650
Olli Etuahob6fa0432016-09-28 16:28:05 +0100651TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
652{
653 TIntermTyped *operandCopy = node.mOperand->deepCopy();
654 ASSERT(operandCopy != nullptr);
655 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000656 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100657}
658
Olli Etuahod7a25242015-08-18 13:49:45 +0300659TIntermBinary::TIntermBinary(const TIntermBinary &node)
660 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
661{
662 TIntermTyped *leftCopy = node.mLeft->deepCopy();
663 TIntermTyped *rightCopy = node.mRight->deepCopy();
664 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
665 mLeft = leftCopy;
666 mRight = rightCopy;
667}
668
669TIntermUnary::TIntermUnary(const TIntermUnary &node)
670 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
671{
672 TIntermTyped *operandCopy = node.mOperand->deepCopy();
673 ASSERT(operandCopy != nullptr);
674 mOperand = operandCopy;
675}
676
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300677TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300678{
Olli Etuahod7a25242015-08-18 13:49:45 +0300679 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300680 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
681 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300682 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300683 mCondition = conditionCopy;
684 mTrueExpression = trueCopy;
685 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300686}
687
Jamie Madillb1a85f42014-08-19 15:23:24 -0400688bool TIntermOperator::isAssignment() const
689{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300690 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400691}
692
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300693bool TIntermOperator::isMultiplication() const
694{
695 switch (mOp)
696 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500697 case EOpMul:
698 case EOpMatrixTimesMatrix:
699 case EOpMatrixTimesVector:
700 case EOpMatrixTimesScalar:
701 case EOpVectorTimesMatrix:
702 case EOpVectorTimesScalar:
703 return true;
704 default:
705 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300706 }
707}
708
Jamie Madillb1a85f42014-08-19 15:23:24 -0400709bool TIntermOperator::isConstructor() const
710{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300711 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400712}
713
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800714bool TIntermOperator::isFunctionCall() const
715{
716 switch (mOp)
717 {
718 case EOpCallFunctionInAST:
719 case EOpCallBuiltInFunction:
720 case EOpCallInternalRawFunction:
721 return true;
722 default:
723 return false;
724 }
725}
726
Olli Etuaho1dded802016-08-18 18:13:13 +0300727TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
728{
729 if (left.isMatrix())
730 {
731 if (right.isMatrix())
732 {
733 return EOpMatrixTimesMatrix;
734 }
735 else
736 {
737 if (right.isVector())
738 {
739 return EOpMatrixTimesVector;
740 }
741 else
742 {
743 return EOpMatrixTimesScalar;
744 }
745 }
746 }
747 else
748 {
749 if (right.isMatrix())
750 {
751 if (left.isVector())
752 {
753 return EOpVectorTimesMatrix;
754 }
755 else
756 {
757 return EOpMatrixTimesScalar;
758 }
759 }
760 else
761 {
762 // Neither operand is a matrix.
763 if (left.isVector() == right.isVector())
764 {
765 // Leave as component product.
766 return EOpMul;
767 }
768 else
769 {
770 return EOpVectorTimesScalar;
771 }
772 }
773 }
774}
775
776TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
777{
778 if (left.isMatrix())
779 {
780 if (right.isMatrix())
781 {
782 return EOpMatrixTimesMatrixAssign;
783 }
784 else
785 {
786 // right should be scalar, but this may not be validated yet.
787 return EOpMatrixTimesScalarAssign;
788 }
789 }
790 else
791 {
792 if (right.isMatrix())
793 {
794 // Left should be a vector, but this may not be validated yet.
795 return EOpVectorTimesMatrixAssign;
796 }
797 else
798 {
799 // Neither operand is a matrix.
800 if (left.isVector() == right.isVector())
801 {
802 // Leave as component product.
803 return EOpMulAssign;
804 }
805 else
806 {
807 // left should be vector and right should be scalar, but this may not be validated
808 // yet.
809 return EOpVectorTimesScalarAssign;
810 }
811 }
812 }
813}
814
Jamie Madillb1a85f42014-08-19 15:23:24 -0400815//
816// Make sure the type of a unary operator is appropriate for its
817// combination of operation and operand type.
818//
Olli Etuahoa2234302016-08-31 12:05:39 +0300819void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400820{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300821 if (mOp == EOpArrayLength)
822 {
823 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
824 setType(TType(EbtInt, EbpUndefined, EvqConst));
825 return;
826 }
827
Olli Etuahoa2234302016-08-31 12:05:39 +0300828 TQualifier resultQualifier = EvqTemporary;
829 if (mOperand->getQualifier() == EvqConst)
830 resultQualifier = EvqConst;
831
832 unsigned char operandPrimarySize =
833 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400834 switch (mOp)
835 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300836 case EOpFloatBitsToInt:
837 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
838 break;
839 case EOpFloatBitsToUint:
840 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
841 break;
842 case EOpIntBitsToFloat:
843 case EOpUintBitsToFloat:
844 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
845 break;
846 case EOpPackSnorm2x16:
847 case EOpPackUnorm2x16:
848 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800849 case EOpPackUnorm4x8:
850 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300851 setType(TType(EbtUInt, EbpHigh, resultQualifier));
852 break;
853 case EOpUnpackSnorm2x16:
854 case EOpUnpackUnorm2x16:
855 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
856 break;
857 case EOpUnpackHalf2x16:
858 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
859 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800860 case EOpUnpackUnorm4x8:
861 case EOpUnpackSnorm4x8:
862 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
863 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300864 case EOpAny:
865 case EOpAll:
866 setType(TType(EbtBool, EbpUndefined, resultQualifier));
867 break;
868 case EOpLength:
869 case EOpDeterminant:
870 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
871 break;
872 case EOpTranspose:
873 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
874 static_cast<unsigned char>(mOperand->getType().getRows()),
875 static_cast<unsigned char>(mOperand->getType().getCols())));
876 break;
877 case EOpIsInf:
878 case EOpIsNan:
879 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
880 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000881 case EOpBitfieldReverse:
882 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
883 break;
884 case EOpBitCount:
885 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
886 break;
887 case EOpFindLSB:
888 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
889 break;
890 case EOpFindMSB:
891 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
892 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300893 default:
894 setType(mOperand->getType());
895 mType.setQualifier(resultQualifier);
896 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400897 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300898}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400899
Olli Etuahob6fa0432016-09-28 16:28:05 +0100900TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
901 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
902 mOperand(operand),
903 mSwizzleOffsets(swizzleOffsets)
904{
905 ASSERT(mSwizzleOffsets.size() <= 4);
906 promote();
907}
908
Olli Etuahoa2234302016-08-31 12:05:39 +0300909TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
910 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
911{
912 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400913}
914
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300915TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
916 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
917{
918 promote();
919}
920
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000921TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
922 : TIntermNode(), mSymbol(symbol)
923{
924 ASSERT(symbol);
925 setLine(line);
926}
927
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300928TIntermTernary::TIntermTernary(TIntermTyped *cond,
929 TIntermTyped *trueExpression,
930 TIntermTyped *falseExpression)
931 : TIntermTyped(trueExpression->getType()),
932 mCondition(cond),
933 mTrueExpression(trueExpression),
934 mFalseExpression(falseExpression)
935{
936 getTypePointer()->setQualifier(
937 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
938}
939
Olli Etuaho81629262017-04-19 11:56:01 +0300940TIntermLoop::TIntermLoop(TLoopType type,
941 TIntermNode *init,
942 TIntermTyped *cond,
943 TIntermTyped *expr,
944 TIntermBlock *body)
945 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
946{
947 // Declaration nodes with no children can appear if all the declarators just added constants to
948 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
949 if (mInit && mInit->getAsDeclarationNode() &&
950 mInit->getAsDeclarationNode()->getSequence()->empty())
951 {
952 mInit = nullptr;
953 }
954}
955
Olli Etuaho923ecef2017-10-11 12:01:38 +0300956TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
957 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
958{
959 // Prune empty false blocks so that there won't be unnecessary operations done on it.
960 if (mFalseBlock && mFalseBlock->getSequence()->empty())
961 {
962 mFalseBlock = nullptr;
963 }
964}
965
966TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
967 : TIntermNode(), mInit(init), mStatementList(statementList)
968{
969 ASSERT(mStatementList);
970}
971
972void TIntermSwitch::setStatementList(TIntermBlock *statementList)
973{
974 ASSERT(statementList);
975 mStatementList = statementList;
976}
977
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300978// static
979TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
980 TIntermTyped *trueExpression,
981 TIntermTyped *falseExpression)
982{
983 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
984 falseExpression->getQualifier() == EvqConst)
985 {
986 return EvqConst;
987 }
988 return EvqTemporary;
989}
990
Olli Etuahoeb7f90f2017-07-07 17:25:23 +0300991TIntermTyped *TIntermTernary::fold()
992{
993 if (mCondition->getAsConstantUnion())
994 {
995 if (mCondition->getAsConstantUnion()->getBConst(0))
996 {
997 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
998 return mTrueExpression;
999 }
1000 else
1001 {
1002 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
1003 return mFalseExpression;
1004 }
1005 }
1006 return this;
1007}
1008
Olli Etuahob6fa0432016-09-28 16:28:05 +01001009void TIntermSwizzle::promote()
1010{
1011 TQualifier resultQualifier = EvqTemporary;
1012 if (mOperand->getQualifier() == EvqConst)
1013 resultQualifier = EvqConst;
1014
1015 auto numFields = mSwizzleOffsets.size();
1016 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1017 static_cast<unsigned char>(numFields)));
1018}
1019
1020bool TIntermSwizzle::hasDuplicateOffsets() const
1021{
1022 int offsetCount[4] = {0u, 0u, 0u, 0u};
1023 for (const auto offset : mSwizzleOffsets)
1024 {
1025 offsetCount[offset]++;
1026 if (offsetCount[offset] > 1)
1027 {
1028 return true;
1029 }
1030 }
1031 return false;
1032}
1033
Olli Etuaho09b04a22016-12-15 13:30:26 +00001034bool TIntermSwizzle::offsetsMatch(int offset) const
1035{
1036 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1037}
1038
Olli Etuahob6fa0432016-09-28 16:28:05 +01001039void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1040{
1041 for (const int offset : mSwizzleOffsets)
1042 {
1043 switch (offset)
1044 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001045 case 0:
1046 *out << "x";
1047 break;
1048 case 1:
1049 *out << "y";
1050 break;
1051 case 2:
1052 *out << "z";
1053 break;
1054 case 3:
1055 *out << "w";
1056 break;
1057 default:
1058 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001059 }
1060 }
1061}
1062
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001063TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1064 const TIntermTyped *left,
1065 const TIntermTyped *right)
1066{
1067 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1068 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1069 right->getQualifier() != EvqConst)
1070 {
1071 return EvqTemporary;
1072 }
1073 return EvqConst;
1074}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001075
1076// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001077void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001078{
Olli Etuaho1dded802016-08-18 18:13:13 +03001079 ASSERT(!isMultiplication() ||
1080 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1081
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001082 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1083 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001084 if (mOp == EOpComma)
1085 {
1086 setType(mRight->getType());
1087 return;
1088 }
1089
Jamie Madillb1a85f42014-08-19 15:23:24 -04001090 // Base assumption: just make the type the same as the left
1091 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001092 setType(mLeft->getType());
1093
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001094 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001095 // Binary operations results in temporary variables unless both
1096 // operands are const.
1097 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1098 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001099 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001100 getTypePointer()->setQualifier(EvqTemporary);
1101 }
1102
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001103 // Handle indexing ops.
1104 switch (mOp)
1105 {
1106 case EOpIndexDirect:
1107 case EOpIndexIndirect:
1108 if (mLeft->isArray())
1109 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001110 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001111 }
1112 else if (mLeft->isMatrix())
1113 {
1114 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1115 static_cast<unsigned char>(mLeft->getRows())));
1116 }
1117 else if (mLeft->isVector())
1118 {
1119 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1120 }
1121 else
1122 {
1123 UNREACHABLE();
1124 }
1125 return;
1126 case EOpIndexDirectStruct:
1127 {
1128 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1129 const int i = mRight->getAsConstantUnion()->getIConst(0);
1130 setType(*fields[i]->type());
1131 getTypePointer()->setQualifier(resultQualifier);
1132 return;
1133 }
1134 case EOpIndexDirectInterfaceBlock:
1135 {
1136 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1137 const int i = mRight->getAsConstantUnion()->getIConst(0);
1138 setType(*fields[i]->type());
1139 getTypePointer()->setQualifier(resultQualifier);
1140 return;
1141 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001142 default:
1143 break;
1144 }
1145
1146 ASSERT(mLeft->isArray() == mRight->isArray());
1147
1148 // The result gets promoted to the highest precision.
1149 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1150 getTypePointer()->setPrecision(higherPrecision);
1151
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001152 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001153
1154 //
1155 // All scalars or structs. Code after this test assumes this case is removed!
1156 //
1157 if (nominalSize == 1)
1158 {
1159 switch (mOp)
1160 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001161 //
1162 // Promote to conditional
1163 //
1164 case EOpEqual:
1165 case EOpNotEqual:
1166 case EOpLessThan:
1167 case EOpGreaterThan:
1168 case EOpLessThanEqual:
1169 case EOpGreaterThanEqual:
1170 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1171 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001172
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001173 //
1174 // And and Or operate on conditionals
1175 //
1176 case EOpLogicalAnd:
1177 case EOpLogicalXor:
1178 case EOpLogicalOr:
1179 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1180 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1181 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001182
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001183 default:
1184 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001185 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001186 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001187 }
1188
1189 // If we reach here, at least one of the operands is vector or matrix.
1190 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001191 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001192
Jamie Madillb1a85f42014-08-19 15:23:24 -04001193 switch (mOp)
1194 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001195 case EOpMul:
1196 break;
1197 case EOpMatrixTimesScalar:
1198 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001199 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001200 setType(TType(basicType, higherPrecision, resultQualifier,
1201 static_cast<unsigned char>(mRight->getCols()),
1202 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001203 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001204 break;
1205 case EOpMatrixTimesVector:
1206 setType(TType(basicType, higherPrecision, resultQualifier,
1207 static_cast<unsigned char>(mLeft->getRows()), 1));
1208 break;
1209 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001210 setType(TType(basicType, higherPrecision, resultQualifier,
1211 static_cast<unsigned char>(mRight->getCols()),
1212 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001213 break;
1214 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001215 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001216 static_cast<unsigned char>(nominalSize), 1));
1217 break;
1218 case EOpVectorTimesMatrix:
1219 setType(TType(basicType, higherPrecision, resultQualifier,
1220 static_cast<unsigned char>(mRight->getCols()), 1));
1221 break;
1222 case EOpMulAssign:
1223 case EOpVectorTimesScalarAssign:
1224 case EOpVectorTimesMatrixAssign:
1225 case EOpMatrixTimesScalarAssign:
1226 case EOpMatrixTimesMatrixAssign:
1227 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1228 break;
1229 case EOpAssign:
1230 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001231 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1232 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1233 break;
1234 case EOpAdd:
1235 case EOpSub:
1236 case EOpDiv:
1237 case EOpIMod:
1238 case EOpBitShiftLeft:
1239 case EOpBitShiftRight:
1240 case EOpBitwiseAnd:
1241 case EOpBitwiseXor:
1242 case EOpBitwiseOr:
1243 case EOpAddAssign:
1244 case EOpSubAssign:
1245 case EOpDivAssign:
1246 case EOpIModAssign:
1247 case EOpBitShiftLeftAssign:
1248 case EOpBitShiftRightAssign:
1249 case EOpBitwiseAndAssign:
1250 case EOpBitwiseXorAssign:
1251 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001252 {
1253 const int secondarySize =
1254 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1255 setType(TType(basicType, higherPrecision, resultQualifier,
1256 static_cast<unsigned char>(nominalSize),
1257 static_cast<unsigned char>(secondarySize)));
1258 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001259 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001260 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001261 case EOpEqual:
1262 case EOpNotEqual:
1263 case EOpLessThan:
1264 case EOpGreaterThan:
1265 case EOpLessThanEqual:
1266 case EOpGreaterThanEqual:
1267 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1268 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001269 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001270 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001271
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001272 case EOpIndexDirect:
1273 case EOpIndexIndirect:
1274 case EOpIndexDirectInterfaceBlock:
1275 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001276 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001277 UNREACHABLE();
1278 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001279 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001280 UNREACHABLE();
1281 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001282 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001283}
1284
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001285const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001286{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001287 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001288 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001289 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001290 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001291 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001292 size_t arrayElementSize = arrayElementType.getObjectSize();
1293 return &mUnionArrayPointer[arrayElementSize * index];
1294 }
1295 else if (isMatrix())
1296 {
1297 ASSERT(index < getType().getCols());
1298 int size = getType().getRows();
1299 return &mUnionArrayPointer[size * index];
1300 }
1301 else if (isVector())
1302 {
1303 ASSERT(index < getType().getNominalSize());
1304 return &mUnionArrayPointer[index];
1305 }
1306 else
1307 {
1308 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001309 return nullptr;
1310 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001311}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001312
Olli Etuahob6fa0432016-09-28 16:28:05 +01001313TIntermTyped *TIntermSwizzle::fold()
1314{
1315 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1316 if (operandConstant == nullptr)
1317 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001318 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001319 }
1320
1321 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1322 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1323 {
1324 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1325 }
1326 return CreateFoldedNode(constArray, this, mType.getQualifier());
1327}
1328
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001329TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1330{
1331 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1332 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1333 switch (mOp)
1334 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001335 case EOpComma:
1336 {
1337 if (mLeft->hasSideEffects())
1338 {
1339 return this;
1340 }
1341 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1342 return mRight;
1343 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001344 case EOpIndexDirect:
1345 {
1346 if (leftConstant == nullptr || rightConstant == nullptr)
1347 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001348 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001349 }
1350 int index = rightConstant->getIConst(0);
1351
1352 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001353 if (!constArray)
1354 {
1355 return this;
1356 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001357 return CreateFoldedNode(constArray, this, mType.getQualifier());
1358 }
1359 case EOpIndexDirectStruct:
1360 {
1361 if (leftConstant == nullptr || rightConstant == nullptr)
1362 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001363 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001364 }
1365 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1366 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1367
1368 size_t previousFieldsSize = 0;
1369 for (size_t i = 0; i < index; ++i)
1370 {
1371 previousFieldsSize += fields[i]->type()->getObjectSize();
1372 }
1373
1374 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1375 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1376 }
1377 case EOpIndexIndirect:
1378 case EOpIndexDirectInterfaceBlock:
1379 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001380 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001381 default:
1382 {
1383 if (leftConstant == nullptr || rightConstant == nullptr)
1384 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001385 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001386 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001387 TConstantUnion *constArray =
1388 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001389 if (!constArray)
1390 {
1391 return this;
1392 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001393
1394 // Nodes may be constant folded without being qualified as constant.
1395 return CreateFoldedNode(constArray, this, mType.getQualifier());
1396 }
1397 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001398}
1399
Olli Etuahof119a262016-08-19 15:54:22 +03001400TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001401{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301402 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001403
1404 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301405 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001406 // The size of runtime-sized arrays may only be determined at runtime.
1407 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001408 {
1409 return this;
1410 }
1411 constArray = new TConstantUnion[1];
1412 constArray->setIConst(mOperand->getOutermostArraySize());
1413 }
1414 else
1415 {
1416 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1417 if (operandConstant == nullptr)
1418 {
1419 return this;
1420 }
1421
1422 switch (mOp)
1423 {
1424 case EOpAny:
1425 case EOpAll:
1426 case EOpLength:
1427 case EOpTranspose:
1428 case EOpDeterminant:
1429 case EOpInverse:
1430 case EOpPackSnorm2x16:
1431 case EOpUnpackSnorm2x16:
1432 case EOpPackUnorm2x16:
1433 case EOpUnpackUnorm2x16:
1434 case EOpPackHalf2x16:
1435 case EOpUnpackHalf2x16:
1436 case EOpPackUnorm4x8:
1437 case EOpPackSnorm4x8:
1438 case EOpUnpackUnorm4x8:
1439 case EOpUnpackSnorm4x8:
1440 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1441 break;
1442 default:
1443 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1444 break;
1445 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301446 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001447 if (constArray == nullptr)
1448 {
1449 return this;
1450 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001451
1452 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001453 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001454}
1455
Olli Etuahof119a262016-08-19 15:54:22 +03001456TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001457{
1458 // Make sure that all params are constant before actual constant folding.
1459 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001460 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001461 if (param->getAsConstantUnion() == nullptr)
1462 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001463 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001464 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001465 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001466 TConstantUnion *constArray = nullptr;
1467 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001468 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001469 else
Olli Etuahof119a262016-08-19 15:54:22 +03001470 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001471
1472 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001473 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001474}
1475
Jamie Madillb1a85f42014-08-19 15:23:24 -04001476//
1477// The fold functions see if an operation on a constant can be done in place,
1478// without generating run-time code.
1479//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001480// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001481//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001482TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1483 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001484 TDiagnostics *diagnostics,
1485 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001486{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001487 const TConstantUnion *leftArray = getUnionArrayPointer();
1488 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001489
Olli Etuahof119a262016-08-19 15:54:22 +03001490 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001491
1492 size_t objectSize = getType().getObjectSize();
1493
1494 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1495 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1496 {
1497 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1498 }
1499 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1500 {
1501 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001502 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001503 objectSize = rightNode->getType().getObjectSize();
1504 }
1505
1506 TConstantUnion *resultArray = nullptr;
1507
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001508 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001509 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001510 case EOpAdd:
1511 resultArray = new TConstantUnion[objectSize];
1512 for (size_t i = 0; i < objectSize; i++)
1513 resultArray[i] =
1514 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1515 break;
1516 case EOpSub:
1517 resultArray = new TConstantUnion[objectSize];
1518 for (size_t i = 0; i < objectSize; i++)
1519 resultArray[i] =
1520 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1521 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001522
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001523 case EOpMul:
1524 case EOpVectorTimesScalar:
1525 case EOpMatrixTimesScalar:
1526 resultArray = new TConstantUnion[objectSize];
1527 for (size_t i = 0; i < objectSize; i++)
1528 resultArray[i] =
1529 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1530 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001531
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001532 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001533 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001534 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001535 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001536
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001537 const int leftCols = getCols();
1538 const int leftRows = getRows();
1539 const int rightCols = rightNode->getType().getCols();
1540 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001541 const int resultCols = rightCols;
1542 const int resultRows = leftRows;
1543
1544 resultArray = new TConstantUnion[resultCols * resultRows];
1545 for (int row = 0; row < resultRows; row++)
1546 {
1547 for (int column = 0; column < resultCols; column++)
1548 {
1549 resultArray[resultRows * column + row].setFConst(0.0f);
1550 for (int i = 0; i < leftCols; i++)
1551 {
1552 resultArray[resultRows * column + row].setFConst(
1553 resultArray[resultRows * column + row].getFConst() +
1554 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001555 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001556 }
1557 }
1558 }
1559 }
1560 break;
1561
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001562 case EOpDiv:
1563 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001564 {
1565 resultArray = new TConstantUnion[objectSize];
1566 for (size_t i = 0; i < objectSize; i++)
1567 {
1568 switch (getType().getBasicType())
1569 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001570 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001571 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001572 ASSERT(op == EOpDiv);
1573 float dividend = leftArray[i].getFConst();
1574 float divisor = rightArray[i].getFConst();
1575 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001576 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001577 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001578 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001579 diagnostics->warning(
1580 getLine(),
1581 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001582 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001583 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001584 }
1585 else
1586 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001587 diagnostics->warning(getLine(),
1588 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001589 bool negativeResult =
1590 std::signbit(dividend) != std::signbit(divisor);
1591 resultArray[i].setFConst(
1592 negativeResult ? -std::numeric_limits<float>::infinity()
1593 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001594 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001595 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001596 else if (gl::isInf(dividend) && gl::isInf(divisor))
1597 {
1598 diagnostics->warning(getLine(),
1599 "Infinity divided by infinity during constant "
1600 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001601 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001602 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1603 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001604 else
1605 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001606 float result = dividend / divisor;
1607 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001608 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001609 diagnostics->warning(
1610 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001611 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001612 }
1613 resultArray[i].setFConst(result);
1614 }
1615 break;
1616 }
1617 case EbtInt:
1618 if (rightArray[i] == 0)
1619 {
1620 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001621 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001622 resultArray[i].setIConst(INT_MAX);
1623 }
1624 else
1625 {
1626 int lhs = leftArray[i].getIConst();
1627 int divisor = rightArray[i].getIConst();
1628 if (op == EOpDiv)
1629 {
1630 // Check for the special case where the minimum representable number
1631 // is
1632 // divided by -1. If left alone this leads to integer overflow in
1633 // C++.
1634 // ESSL 3.00.6 section 4.1.3 Integers:
1635 // "However, for the case where the minimum representable value is
1636 // divided by -1, it is allowed to return either the minimum
1637 // representable value or the maximum representable value."
1638 if (lhs == -0x7fffffff - 1 && divisor == -1)
1639 {
1640 resultArray[i].setIConst(0x7fffffff);
1641 }
1642 else
1643 {
1644 resultArray[i].setIConst(lhs / divisor);
1645 }
Olli Etuahod4453572016-09-27 13:21:46 +01001646 }
1647 else
1648 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001649 ASSERT(op == EOpIMod);
1650 if (lhs < 0 || divisor < 0)
1651 {
1652 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1653 // when
1654 // either one of the operands is negative.
1655 diagnostics->warning(getLine(),
1656 "Negative modulus operator operand "
1657 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001658 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001659 resultArray[i].setIConst(0);
1660 }
1661 else
1662 {
1663 resultArray[i].setIConst(lhs % divisor);
1664 }
Olli Etuahod4453572016-09-27 13:21:46 +01001665 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001666 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001667 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001668
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001669 case EbtUInt:
1670 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001671 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001672 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001673 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001674 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001675 }
1676 else
1677 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001678 if (op == EOpDiv)
1679 {
1680 resultArray[i].setUConst(leftArray[i].getUConst() /
1681 rightArray[i].getUConst());
1682 }
1683 else
1684 {
1685 ASSERT(op == EOpIMod);
1686 resultArray[i].setUConst(leftArray[i].getUConst() %
1687 rightArray[i].getUConst());
1688 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001689 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001690 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001691
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001692 default:
1693 UNREACHABLE();
1694 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001695 }
1696 }
1697 }
1698 break;
1699
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001700 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001701 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001702 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001703 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001704
1705 const int matrixCols = getCols();
1706 const int matrixRows = getRows();
1707
1708 resultArray = new TConstantUnion[matrixRows];
1709
1710 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1711 {
1712 resultArray[matrixRow].setFConst(0.0f);
1713 for (int col = 0; col < matrixCols; col++)
1714 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001715 resultArray[matrixRow].setFConst(
1716 resultArray[matrixRow].getFConst() +
1717 leftArray[col * matrixRows + matrixRow].getFConst() *
1718 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001719 }
1720 }
1721 }
1722 break;
1723
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001724 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001725 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001726 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001727 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001728
1729 const int matrixCols = rightNode->getType().getCols();
1730 const int matrixRows = rightNode->getType().getRows();
1731
1732 resultArray = new TConstantUnion[matrixCols];
1733
1734 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1735 {
1736 resultArray[matrixCol].setFConst(0.0f);
1737 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1738 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001739 resultArray[matrixCol].setFConst(
1740 resultArray[matrixCol].getFConst() +
1741 leftArray[matrixRow].getFConst() *
1742 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001743 }
1744 }
1745 }
1746 break;
1747
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001748 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001749 {
1750 resultArray = new TConstantUnion[objectSize];
1751 for (size_t i = 0; i < objectSize; i++)
1752 {
1753 resultArray[i] = leftArray[i] && rightArray[i];
1754 }
1755 }
1756 break;
1757
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001758 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001759 {
1760 resultArray = new TConstantUnion[objectSize];
1761 for (size_t i = 0; i < objectSize; i++)
1762 {
1763 resultArray[i] = leftArray[i] || rightArray[i];
1764 }
1765 }
1766 break;
1767
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001768 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001769 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001770 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001771 resultArray = new TConstantUnion[objectSize];
1772 for (size_t i = 0; i < objectSize; i++)
1773 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001774 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001775 }
1776 }
1777 break;
1778
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001779 case EOpBitwiseAnd:
1780 resultArray = new TConstantUnion[objectSize];
1781 for (size_t i = 0; i < objectSize; i++)
1782 resultArray[i] = leftArray[i] & rightArray[i];
1783 break;
1784 case EOpBitwiseXor:
1785 resultArray = new TConstantUnion[objectSize];
1786 for (size_t i = 0; i < objectSize; i++)
1787 resultArray[i] = leftArray[i] ^ rightArray[i];
1788 break;
1789 case EOpBitwiseOr:
1790 resultArray = new TConstantUnion[objectSize];
1791 for (size_t i = 0; i < objectSize; i++)
1792 resultArray[i] = leftArray[i] | rightArray[i];
1793 break;
1794 case EOpBitShiftLeft:
1795 resultArray = new TConstantUnion[objectSize];
1796 for (size_t i = 0; i < objectSize; i++)
1797 resultArray[i] =
1798 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1799 break;
1800 case EOpBitShiftRight:
1801 resultArray = new TConstantUnion[objectSize];
1802 for (size_t i = 0; i < objectSize; i++)
1803 resultArray[i] =
1804 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1805 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001806
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001807 case EOpLessThan:
1808 ASSERT(objectSize == 1);
1809 resultArray = new TConstantUnion[1];
1810 resultArray->setBConst(*leftArray < *rightArray);
1811 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001812
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001813 case EOpGreaterThan:
1814 ASSERT(objectSize == 1);
1815 resultArray = new TConstantUnion[1];
1816 resultArray->setBConst(*leftArray > *rightArray);
1817 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001818
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001819 case EOpLessThanEqual:
1820 ASSERT(objectSize == 1);
1821 resultArray = new TConstantUnion[1];
1822 resultArray->setBConst(!(*leftArray > *rightArray));
1823 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001824
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001825 case EOpGreaterThanEqual:
1826 ASSERT(objectSize == 1);
1827 resultArray = new TConstantUnion[1];
1828 resultArray->setBConst(!(*leftArray < *rightArray));
1829 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001830
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001831 case EOpEqual:
1832 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001833 {
1834 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001835 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001836 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001837 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001838 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001839 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001840 equal = false;
1841 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001842 }
1843 }
1844 if (op == EOpEqual)
1845 {
1846 resultArray->setBConst(equal);
1847 }
1848 else
1849 {
1850 resultArray->setBConst(!equal);
1851 }
1852 }
1853 break;
1854
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001855 default:
1856 UNREACHABLE();
1857 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001858 }
1859 return resultArray;
1860}
1861
Olli Etuahof119a262016-08-19 15:54:22 +03001862// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1863// code. Returns the constant value to keep using. Nullptr should not be returned.
1864TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001865{
Olli Etuahof119a262016-08-19 15:54:22 +03001866 // Do operations where the return type may have a different number of components compared to the
1867 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001868
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001869 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001870 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301871
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001872 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301873 TConstantUnion *resultArray = nullptr;
1874 switch (op)
1875 {
Olli Etuahof119a262016-08-19 15:54:22 +03001876 case EOpAny:
1877 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301878 resultArray = new TConstantUnion();
1879 resultArray->setBConst(false);
1880 for (size_t i = 0; i < objectSize; i++)
1881 {
1882 if (operandArray[i].getBConst())
1883 {
1884 resultArray->setBConst(true);
1885 break;
1886 }
1887 }
1888 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301889
Olli Etuahof119a262016-08-19 15:54:22 +03001890 case EOpAll:
1891 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301892 resultArray = new TConstantUnion();
1893 resultArray->setBConst(true);
1894 for (size_t i = 0; i < objectSize; i++)
1895 {
1896 if (!operandArray[i].getBConst())
1897 {
1898 resultArray->setBConst(false);
1899 break;
1900 }
1901 }
1902 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301903
Olli Etuahof119a262016-08-19 15:54:22 +03001904 case EOpLength:
1905 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301906 resultArray = new TConstantUnion();
1907 resultArray->setFConst(VectorLength(operandArray, objectSize));
1908 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301909
Olli Etuahof119a262016-08-19 15:54:22 +03001910 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301911 {
Olli Etuahof119a262016-08-19 15:54:22 +03001912 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301913 resultArray = new TConstantUnion[objectSize];
1914 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001915 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301916 SetUnionArrayFromMatrix(result, resultArray);
1917 break;
1918 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301919
Olli Etuahof119a262016-08-19 15:54:22 +03001920 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301921 {
Olli Etuahof119a262016-08-19 15:54:22 +03001922 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301923 unsigned int size = getType().getNominalSize();
1924 ASSERT(size >= 2 && size <= 4);
1925 resultArray = new TConstantUnion();
1926 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1927 break;
1928 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301929
Olli Etuahof119a262016-08-19 15:54:22 +03001930 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301931 {
Olli Etuahof119a262016-08-19 15:54:22 +03001932 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301933 unsigned int size = getType().getNominalSize();
1934 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001935 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301936 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1937 SetUnionArrayFromMatrix(result, resultArray);
1938 break;
1939 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301940
Olli Etuahof119a262016-08-19 15:54:22 +03001941 case EOpPackSnorm2x16:
1942 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301943 ASSERT(getType().getNominalSize() == 2);
1944 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001945 resultArray->setUConst(
1946 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301947 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301948
Olli Etuahof119a262016-08-19 15:54:22 +03001949 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301950 {
Olli Etuahof119a262016-08-19 15:54:22 +03001951 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301952 resultArray = new TConstantUnion[2];
1953 float f1, f2;
1954 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1955 resultArray[0].setFConst(f1);
1956 resultArray[1].setFConst(f2);
1957 break;
1958 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301959
Olli Etuahof119a262016-08-19 15:54:22 +03001960 case EOpPackUnorm2x16:
1961 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301962 ASSERT(getType().getNominalSize() == 2);
1963 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001964 resultArray->setUConst(
1965 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301966 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301967
Olli Etuahof119a262016-08-19 15:54:22 +03001968 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301969 {
Olli Etuahof119a262016-08-19 15:54:22 +03001970 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301971 resultArray = new TConstantUnion[2];
1972 float f1, f2;
1973 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1974 resultArray[0].setFConst(f1);
1975 resultArray[1].setFConst(f2);
1976 break;
1977 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301978
Olli Etuahof119a262016-08-19 15:54:22 +03001979 case EOpPackHalf2x16:
1980 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301981 ASSERT(getType().getNominalSize() == 2);
1982 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001983 resultArray->setUConst(
1984 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301985 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301986
Olli Etuahof119a262016-08-19 15:54:22 +03001987 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301988 {
Olli Etuahof119a262016-08-19 15:54:22 +03001989 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301990 resultArray = new TConstantUnion[2];
1991 float f1, f2;
1992 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1993 resultArray[0].setFConst(f1);
1994 resultArray[1].setFConst(f2);
1995 break;
1996 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301997
Olli Etuaho25aef452017-01-29 16:15:44 -08001998 case EOpPackUnorm4x8:
1999 {
2000 ASSERT(getType().getBasicType() == EbtFloat);
2001 resultArray = new TConstantUnion();
2002 resultArray->setUConst(
2003 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2004 operandArray[2].getFConst(), operandArray[3].getFConst()));
2005 break;
2006 }
2007 case EOpPackSnorm4x8:
2008 {
2009 ASSERT(getType().getBasicType() == EbtFloat);
2010 resultArray = new TConstantUnion();
2011 resultArray->setUConst(
2012 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2013 operandArray[2].getFConst(), operandArray[3].getFConst()));
2014 break;
2015 }
2016 case EOpUnpackUnorm4x8:
2017 {
2018 ASSERT(getType().getBasicType() == EbtUInt);
2019 resultArray = new TConstantUnion[4];
2020 float f[4];
2021 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2022 for (size_t i = 0; i < 4; ++i)
2023 {
2024 resultArray[i].setFConst(f[i]);
2025 }
2026 break;
2027 }
2028 case EOpUnpackSnorm4x8:
2029 {
2030 ASSERT(getType().getBasicType() == EbtUInt);
2031 resultArray = new TConstantUnion[4];
2032 float f[4];
2033 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2034 for (size_t i = 0; i < 4; ++i)
2035 {
2036 resultArray[i].setFConst(f[i]);
2037 }
2038 break;
2039 }
2040
Olli Etuahof119a262016-08-19 15:54:22 +03002041 default:
2042 UNREACHABLE();
2043 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302044 }
2045
2046 return resultArray;
2047}
2048
Olli Etuahof119a262016-08-19 15:54:22 +03002049TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2050 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302051{
Olli Etuahof119a262016-08-19 15:54:22 +03002052 // Do unary operations where each component of the result is computed based on the corresponding
2053 // component of the operand. Also folds normalize, though the divisor in that case takes all
2054 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302055
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002056 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002057 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002058
2059 size_t objectSize = getType().getObjectSize();
2060
Arun Patoleab2b9a22015-07-06 18:27:56 +05302061 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2062 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302063 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002064 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302065 {
Olli Etuahof119a262016-08-19 15:54:22 +03002066 case EOpNegative:
2067 switch (getType().getBasicType())
2068 {
2069 case EbtFloat:
2070 resultArray[i].setFConst(-operandArray[i].getFConst());
2071 break;
2072 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002073 if (operandArray[i] == std::numeric_limits<int>::min())
2074 {
2075 // The minimum representable integer doesn't have a positive
2076 // counterpart, rather the negation overflows and in ESSL is supposed to
2077 // wrap back to the minimum representable integer. Make sure that we
2078 // don't actually let the negation overflow, which has undefined
2079 // behavior in C++.
2080 resultArray[i].setIConst(std::numeric_limits<int>::min());
2081 }
2082 else
2083 {
2084 resultArray[i].setIConst(-operandArray[i].getIConst());
2085 }
Olli Etuahof119a262016-08-19 15:54:22 +03002086 break;
2087 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002088 if (operandArray[i] == 0x80000000u)
2089 {
2090 resultArray[i].setUConst(0x80000000u);
2091 }
2092 else
2093 {
2094 resultArray[i].setUConst(static_cast<unsigned int>(
2095 -static_cast<int>(operandArray[i].getUConst())));
2096 }
Olli Etuahof119a262016-08-19 15:54:22 +03002097 break;
2098 default:
2099 UNREACHABLE();
2100 return nullptr;
2101 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302102 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302103
Olli Etuahof119a262016-08-19 15:54:22 +03002104 case EOpPositive:
2105 switch (getType().getBasicType())
2106 {
2107 case EbtFloat:
2108 resultArray[i].setFConst(operandArray[i].getFConst());
2109 break;
2110 case EbtInt:
2111 resultArray[i].setIConst(operandArray[i].getIConst());
2112 break;
2113 case EbtUInt:
2114 resultArray[i].setUConst(static_cast<unsigned int>(
2115 static_cast<int>(operandArray[i].getUConst())));
2116 break;
2117 default:
2118 UNREACHABLE();
2119 return nullptr;
2120 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302121 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302122
Olli Etuahof119a262016-08-19 15:54:22 +03002123 case EOpLogicalNot:
2124 switch (getType().getBasicType())
2125 {
2126 case EbtBool:
2127 resultArray[i].setBConst(!operandArray[i].getBConst());
2128 break;
2129 default:
2130 UNREACHABLE();
2131 return nullptr;
2132 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302133 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302134
Olli Etuahof119a262016-08-19 15:54:22 +03002135 case EOpBitwiseNot:
2136 switch (getType().getBasicType())
2137 {
2138 case EbtInt:
2139 resultArray[i].setIConst(~operandArray[i].getIConst());
2140 break;
2141 case EbtUInt:
2142 resultArray[i].setUConst(~operandArray[i].getUConst());
2143 break;
2144 default:
2145 UNREACHABLE();
2146 return nullptr;
2147 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302148 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302149
Olli Etuahof119a262016-08-19 15:54:22 +03002150 case EOpRadians:
2151 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302152 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2153 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302154
Olli Etuahof119a262016-08-19 15:54:22 +03002155 case EOpDegrees:
2156 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302157 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2158 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302159
Olli Etuahof119a262016-08-19 15:54:22 +03002160 case EOpSin:
2161 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302162 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302163
Olli Etuahof119a262016-08-19 15:54:22 +03002164 case EOpCos:
2165 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2166 break;
2167
2168 case EOpTan:
2169 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2170 break;
2171
2172 case EOpAsin:
2173 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2174 // 0.
2175 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2176 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2177 diagnostics, &resultArray[i]);
2178 else
2179 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2180 break;
2181
2182 case EOpAcos:
2183 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2184 // 0.
2185 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2186 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2187 diagnostics, &resultArray[i]);
2188 else
2189 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2190 break;
2191
2192 case EOpAtan:
2193 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2194 break;
2195
2196 case EOpSinh:
2197 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2198 break;
2199
2200 case EOpCosh:
2201 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2202 break;
2203
2204 case EOpTanh:
2205 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2206 break;
2207
2208 case EOpAsinh:
2209 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2210 break;
2211
2212 case EOpAcosh:
2213 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2214 if (operandArray[i].getFConst() < 1.0f)
2215 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2216 diagnostics, &resultArray[i]);
2217 else
2218 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2219 break;
2220
2221 case EOpAtanh:
2222 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2223 // 0.
2224 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2225 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2226 diagnostics, &resultArray[i]);
2227 else
2228 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2229 break;
2230
2231 case EOpAbs:
2232 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302233 {
Olli Etuahof119a262016-08-19 15:54:22 +03002234 case EbtFloat:
2235 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2236 break;
2237 case EbtInt:
2238 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2239 break;
2240 default:
2241 UNREACHABLE();
2242 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302243 }
2244 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002245
2246 case EOpSign:
2247 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302248 {
Olli Etuahof119a262016-08-19 15:54:22 +03002249 case EbtFloat:
2250 {
2251 float fConst = operandArray[i].getFConst();
2252 float fResult = 0.0f;
2253 if (fConst > 0.0f)
2254 fResult = 1.0f;
2255 else if (fConst < 0.0f)
2256 fResult = -1.0f;
2257 resultArray[i].setFConst(fResult);
2258 break;
2259 }
2260 case EbtInt:
2261 {
2262 int iConst = operandArray[i].getIConst();
2263 int iResult = 0;
2264 if (iConst > 0)
2265 iResult = 1;
2266 else if (iConst < 0)
2267 iResult = -1;
2268 resultArray[i].setIConst(iResult);
2269 break;
2270 }
2271 default:
2272 UNREACHABLE();
2273 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302274 }
2275 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302276
Olli Etuahof119a262016-08-19 15:54:22 +03002277 case EOpFloor:
2278 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2279 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302280
Olli Etuahof119a262016-08-19 15:54:22 +03002281 case EOpTrunc:
2282 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2283 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302284
Olli Etuahof119a262016-08-19 15:54:22 +03002285 case EOpRound:
2286 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2287 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302288
Olli Etuahof119a262016-08-19 15:54:22 +03002289 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302290 {
Olli Etuahof119a262016-08-19 15:54:22 +03002291 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302292 float x = operandArray[i].getFConst();
2293 float result;
2294 float fractPart = modff(x, &result);
2295 if (fabsf(fractPart) == 0.5f)
2296 result = 2.0f * roundf(x / 2.0f);
2297 else
2298 result = roundf(x);
2299 resultArray[i].setFConst(result);
2300 break;
2301 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302302
Olli Etuahof119a262016-08-19 15:54:22 +03002303 case EOpCeil:
2304 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2305 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302306
Olli Etuahof119a262016-08-19 15:54:22 +03002307 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302308 {
Olli Etuahof119a262016-08-19 15:54:22 +03002309 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302310 float x = operandArray[i].getFConst();
2311 resultArray[i].setFConst(x - floorf(x));
2312 break;
2313 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302314
Olli Etuahof119a262016-08-19 15:54:22 +03002315 case EOpIsNan:
2316 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302317 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2318 break;
Arun Patole551279e2015-07-07 18:18:23 +05302319
Olli Etuahof119a262016-08-19 15:54:22 +03002320 case EOpIsInf:
2321 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302322 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2323 break;
Arun Patole551279e2015-07-07 18:18:23 +05302324
Olli Etuahof119a262016-08-19 15:54:22 +03002325 case EOpFloatBitsToInt:
2326 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302327 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2328 break;
Arun Patole551279e2015-07-07 18:18:23 +05302329
Olli Etuahof119a262016-08-19 15:54:22 +03002330 case EOpFloatBitsToUint:
2331 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302332 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2333 break;
Arun Patole551279e2015-07-07 18:18:23 +05302334
Olli Etuahof119a262016-08-19 15:54:22 +03002335 case EOpIntBitsToFloat:
2336 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302337 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2338 break;
Arun Patole551279e2015-07-07 18:18:23 +05302339
Olli Etuahof119a262016-08-19 15:54:22 +03002340 case EOpUintBitsToFloat:
2341 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302342 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2343 break;
Arun Patole551279e2015-07-07 18:18:23 +05302344
Olli Etuahof119a262016-08-19 15:54:22 +03002345 case EOpExp:
2346 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2347 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302348
Olli Etuahof119a262016-08-19 15:54:22 +03002349 case EOpLog:
2350 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2351 if (operandArray[i].getFConst() <= 0.0f)
2352 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2353 diagnostics, &resultArray[i]);
2354 else
2355 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2356 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302357
Olli Etuahof119a262016-08-19 15:54:22 +03002358 case EOpExp2:
2359 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2360 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302361
Olli Etuahof119a262016-08-19 15:54:22 +03002362 case EOpLog2:
2363 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2364 // And log2f is not available on some plarforms like old android, so just using
2365 // log(x)/log(2) here.
2366 if (operandArray[i].getFConst() <= 0.0f)
2367 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2368 diagnostics, &resultArray[i]);
2369 else
2370 {
2371 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2372 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2373 }
2374 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302375
Olli Etuahof119a262016-08-19 15:54:22 +03002376 case EOpSqrt:
2377 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2378 if (operandArray[i].getFConst() < 0.0f)
2379 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2380 diagnostics, &resultArray[i]);
2381 else
2382 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2383 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302384
Olli Etuahof119a262016-08-19 15:54:22 +03002385 case EOpInverseSqrt:
2386 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2387 // so getting the square root first using builtin function sqrt() and then taking
2388 // its inverse.
2389 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2390 // result to 0.
2391 if (operandArray[i].getFConst() <= 0.0f)
2392 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2393 diagnostics, &resultArray[i]);
2394 else
2395 {
2396 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2397 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2398 }
2399 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302400
Olli Etuahod68924e2017-01-02 17:34:40 +00002401 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002402 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302403 resultArray[i].setBConst(!operandArray[i].getBConst());
2404 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302405
Olli Etuahof119a262016-08-19 15:54:22 +03002406 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302407 {
Olli Etuahof119a262016-08-19 15:54:22 +03002408 ASSERT(getType().getBasicType() == EbtFloat);
2409 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302410 float length = VectorLength(operandArray, objectSize);
2411 if (length)
2412 resultArray[i].setFConst(x / length);
2413 else
Olli Etuahof119a262016-08-19 15:54:22 +03002414 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2415 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302416 break;
2417 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002418 case EOpBitfieldReverse:
2419 {
2420 uint32_t value;
2421 if (getType().getBasicType() == EbtInt)
2422 {
2423 value = static_cast<uint32_t>(operandArray[i].getIConst());
2424 }
2425 else
2426 {
2427 ASSERT(getType().getBasicType() == EbtUInt);
2428 value = operandArray[i].getUConst();
2429 }
2430 uint32_t result = gl::BitfieldReverse(value);
2431 if (getType().getBasicType() == EbtInt)
2432 {
2433 resultArray[i].setIConst(static_cast<int32_t>(result));
2434 }
2435 else
2436 {
2437 resultArray[i].setUConst(result);
2438 }
2439 break;
2440 }
2441 case EOpBitCount:
2442 {
2443 uint32_t value;
2444 if (getType().getBasicType() == EbtInt)
2445 {
2446 value = static_cast<uint32_t>(operandArray[i].getIConst());
2447 }
2448 else
2449 {
2450 ASSERT(getType().getBasicType() == EbtUInt);
2451 value = operandArray[i].getUConst();
2452 }
2453 int result = gl::BitCount(value);
2454 resultArray[i].setIConst(result);
2455 break;
2456 }
2457 case EOpFindLSB:
2458 {
2459 uint32_t value;
2460 if (getType().getBasicType() == EbtInt)
2461 {
2462 value = static_cast<uint32_t>(operandArray[i].getIConst());
2463 }
2464 else
2465 {
2466 ASSERT(getType().getBasicType() == EbtUInt);
2467 value = operandArray[i].getUConst();
2468 }
2469 resultArray[i].setIConst(gl::FindLSB(value));
2470 break;
2471 }
2472 case EOpFindMSB:
2473 {
2474 uint32_t value;
2475 if (getType().getBasicType() == EbtInt)
2476 {
2477 int intValue = operandArray[i].getIConst();
2478 value = static_cast<uint32_t>(intValue);
2479 if (intValue < 0)
2480 {
2481 // Look for zero instead of one in value. This also handles the intValue ==
2482 // -1 special case, where the return value needs to be -1.
2483 value = ~value;
2484 }
2485 }
2486 else
2487 {
2488 ASSERT(getType().getBasicType() == EbtUInt);
2489 value = operandArray[i].getUConst();
2490 }
2491 resultArray[i].setIConst(gl::FindMSB(value));
2492 break;
2493 }
Olli Etuahof119a262016-08-19 15:54:22 +03002494 case EOpDFdx:
2495 case EOpDFdy:
2496 case EOpFwidth:
2497 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302498 // Derivatives of constant arguments should be 0.
2499 resultArray[i].setFConst(0.0f);
2500 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302501
Olli Etuahof119a262016-08-19 15:54:22 +03002502 default:
2503 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302504 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302505 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002506
Arun Patoleab2b9a22015-07-06 18:27:56 +05302507 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002508}
2509
Olli Etuahof119a262016-08-19 15:54:22 +03002510void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2511 FloatTypeUnaryFunc builtinFunc,
2512 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302513{
2514 ASSERT(builtinFunc);
2515
Olli Etuahof119a262016-08-19 15:54:22 +03002516 ASSERT(getType().getBasicType() == EbtFloat);
2517 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302518}
2519
Jamie Madillb1a85f42014-08-19 15:23:24 -04002520// static
Olli Etuahof119a262016-08-19 15:54:22 +03002521TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002522{
2523 ASSERT(aggregate->getSequence()->size() > 0u);
2524 size_t resultSize = aggregate->getType().getObjectSize();
2525 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2526 TBasicType basicType = aggregate->getBasicType();
2527
2528 size_t resultIndex = 0u;
2529
2530 if (aggregate->getSequence()->size() == 1u)
2531 {
2532 TIntermNode *argument = aggregate->getSequence()->front();
2533 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2534 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2535 // Check the special case of constructing a matrix diagonal from a single scalar,
2536 // or a vector from a single scalar.
2537 if (argumentConstant->getType().getObjectSize() == 1u)
2538 {
2539 if (aggregate->isMatrix())
2540 {
2541 int resultCols = aggregate->getType().getCols();
2542 int resultRows = aggregate->getType().getRows();
2543 for (int col = 0; col < resultCols; ++col)
2544 {
2545 for (int row = 0; row < resultRows; ++row)
2546 {
2547 if (col == row)
2548 {
2549 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2550 }
2551 else
2552 {
2553 resultArray[resultIndex].setFConst(0.0f);
2554 }
2555 ++resultIndex;
2556 }
2557 }
2558 }
2559 else
2560 {
2561 while (resultIndex < resultSize)
2562 {
2563 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2564 ++resultIndex;
2565 }
2566 }
2567 ASSERT(resultIndex == resultSize);
2568 return resultArray;
2569 }
2570 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2571 {
2572 // The special case of constructing a matrix from a matrix.
2573 int argumentCols = argumentConstant->getType().getCols();
2574 int argumentRows = argumentConstant->getType().getRows();
2575 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002576 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002577 for (int col = 0; col < resultCols; ++col)
2578 {
2579 for (int row = 0; row < resultRows; ++row)
2580 {
2581 if (col < argumentCols && row < argumentRows)
2582 {
2583 resultArray[resultIndex].cast(basicType,
2584 argumentUnionArray[col * argumentRows + row]);
2585 }
2586 else if (col == row)
2587 {
2588 resultArray[resultIndex].setFConst(1.0f);
2589 }
2590 else
2591 {
2592 resultArray[resultIndex].setFConst(0.0f);
2593 }
2594 ++resultIndex;
2595 }
2596 }
2597 ASSERT(resultIndex == resultSize);
2598 return resultArray;
2599 }
2600 }
2601
2602 for (TIntermNode *&argument : *aggregate->getSequence())
2603 {
2604 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2605 size_t argumentSize = argumentConstant->getType().getObjectSize();
2606 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2607 for (size_t i = 0u; i < argumentSize; ++i)
2608 {
2609 if (resultIndex >= resultSize)
2610 break;
2611 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2612 ++resultIndex;
2613 }
2614 }
2615 ASSERT(resultIndex == resultSize);
2616 return resultArray;
2617}
2618
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002619bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2620{
2621 switch (op)
2622 {
2623 case EOpAtan:
2624 case EOpPow:
2625 case EOpMod:
2626 case EOpMin:
2627 case EOpMax:
2628 case EOpClamp:
2629 case EOpMix:
2630 case EOpStep:
2631 case EOpSmoothStep:
2632 case EOpLdexp:
2633 case EOpMulMatrixComponentWise:
2634 case EOpOuterProduct:
2635 case EOpEqualComponentWise:
2636 case EOpNotEqualComponentWise:
2637 case EOpLessThanComponentWise:
2638 case EOpLessThanEqualComponentWise:
2639 case EOpGreaterThanComponentWise:
2640 case EOpGreaterThanEqualComponentWise:
2641 case EOpDistance:
2642 case EOpDot:
2643 case EOpCross:
2644 case EOpFaceforward:
2645 case EOpReflect:
2646 case EOpRefract:
2647 case EOpBitfieldExtract:
2648 case EOpBitfieldInsert:
2649 return true;
2650 default:
2651 return false;
2652 }
2653}
2654
Olli Etuaho1d122782015-11-06 15:35:17 +02002655// static
Olli Etuahof119a262016-08-19 15:54:22 +03002656TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2657 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302658{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002659 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002660 TIntermSequence *arguments = aggregate->getSequence();
2661 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2662 std::vector<const TConstantUnion *> unionArrays(argsCount);
2663 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002664 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302665 TBasicType basicType = EbtVoid;
2666 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002667 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302668 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002669 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2670 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302671
2672 if (i == 0)
2673 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002674 basicType = argConstant->getType().getBasicType();
2675 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302676 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002677 unionArrays[i] = argConstant->getUnionArrayPointer();
2678 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002679 if (objectSizes[i] > maxObjectSize)
2680 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302681 }
2682
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002683 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302684 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002685 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302686 if (objectSizes[i] != maxObjectSize)
2687 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2688 }
Arun Patole274f0702015-05-05 13:33:30 +05302689
Olli Etuahob43846e2015-06-02 18:18:57 +03002690 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002691
2692 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302693 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002694 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302695 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002696 ASSERT(basicType == EbtFloat);
2697 resultArray = new TConstantUnion[maxObjectSize];
2698 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302699 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002700 float y = unionArrays[0][i].getFConst();
2701 float x = unionArrays[1][i].getFConst();
2702 // Results are undefined if x and y are both 0.
2703 if (x == 0.0f && y == 0.0f)
2704 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2705 else
2706 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302707 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002708 break;
2709 }
Arun Patolebf790422015-05-18 17:53:04 +05302710
Olli Etuaho51182ab2017-01-22 00:12:29 +00002711 case EOpPow:
2712 {
2713 ASSERT(basicType == EbtFloat);
2714 resultArray = new TConstantUnion[maxObjectSize];
2715 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302716 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002717 float x = unionArrays[0][i].getFConst();
2718 float y = unionArrays[1][i].getFConst();
2719 // Results are undefined if x < 0.
2720 // Results are undefined if x = 0 and y <= 0.
2721 if (x < 0.0f)
2722 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2723 else if (x == 0.0f && y <= 0.0f)
2724 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2725 else
2726 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302727 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002728 break;
2729 }
Arun Patolebf790422015-05-18 17:53:04 +05302730
Olli Etuaho51182ab2017-01-22 00:12:29 +00002731 case EOpMod:
2732 {
2733 ASSERT(basicType == EbtFloat);
2734 resultArray = new TConstantUnion[maxObjectSize];
2735 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302736 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002737 float x = unionArrays[0][i].getFConst();
2738 float y = unionArrays[1][i].getFConst();
2739 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302740 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002741 break;
2742 }
Arun Patolebf790422015-05-18 17:53:04 +05302743
Olli Etuaho51182ab2017-01-22 00:12:29 +00002744 case EOpMin:
2745 {
2746 resultArray = new TConstantUnion[maxObjectSize];
2747 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302748 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002749 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302750 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002751 case EbtFloat:
2752 resultArray[i].setFConst(
2753 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2754 break;
2755 case EbtInt:
2756 resultArray[i].setIConst(
2757 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2758 break;
2759 case EbtUInt:
2760 resultArray[i].setUConst(
2761 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2762 break;
2763 default:
2764 UNREACHABLE();
2765 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302766 }
2767 }
2768 break;
Arun Patole274f0702015-05-05 13:33:30 +05302769 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002770
2771 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302772 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002773 resultArray = new TConstantUnion[maxObjectSize];
2774 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302775 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002776 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302777 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002778 case EbtFloat:
2779 resultArray[i].setFConst(
2780 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2781 break;
2782 case EbtInt:
2783 resultArray[i].setIConst(
2784 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2785 break;
2786 case EbtUInt:
2787 resultArray[i].setUConst(
2788 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2789 break;
2790 default:
2791 UNREACHABLE();
2792 break;
Arun Patole274f0702015-05-05 13:33:30 +05302793 }
2794 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002795 break;
Arun Patole274f0702015-05-05 13:33:30 +05302796 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002797
2798 case EOpStep:
2799 {
2800 ASSERT(basicType == EbtFloat);
2801 resultArray = new TConstantUnion[maxObjectSize];
2802 for (size_t i = 0; i < maxObjectSize; i++)
2803 resultArray[i].setFConst(
2804 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2805 break;
2806 }
2807
2808 case EOpLessThanComponentWise:
2809 {
2810 resultArray = new TConstantUnion[maxObjectSize];
2811 for (size_t i = 0; i < maxObjectSize; i++)
2812 {
2813 switch (basicType)
2814 {
2815 case EbtFloat:
2816 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2817 unionArrays[1][i].getFConst());
2818 break;
2819 case EbtInt:
2820 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2821 unionArrays[1][i].getIConst());
2822 break;
2823 case EbtUInt:
2824 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2825 unionArrays[1][i].getUConst());
2826 break;
2827 default:
2828 UNREACHABLE();
2829 break;
2830 }
2831 }
2832 break;
2833 }
2834
2835 case EOpLessThanEqualComponentWise:
2836 {
2837 resultArray = new TConstantUnion[maxObjectSize];
2838 for (size_t i = 0; i < maxObjectSize; i++)
2839 {
2840 switch (basicType)
2841 {
2842 case EbtFloat:
2843 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2844 unionArrays[1][i].getFConst());
2845 break;
2846 case EbtInt:
2847 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2848 unionArrays[1][i].getIConst());
2849 break;
2850 case EbtUInt:
2851 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2852 unionArrays[1][i].getUConst());
2853 break;
2854 default:
2855 UNREACHABLE();
2856 break;
2857 }
2858 }
2859 break;
2860 }
2861
2862 case EOpGreaterThanComponentWise:
2863 {
2864 resultArray = new TConstantUnion[maxObjectSize];
2865 for (size_t i = 0; i < maxObjectSize; i++)
2866 {
2867 switch (basicType)
2868 {
2869 case EbtFloat:
2870 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2871 unionArrays[1][i].getFConst());
2872 break;
2873 case EbtInt:
2874 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2875 unionArrays[1][i].getIConst());
2876 break;
2877 case EbtUInt:
2878 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2879 unionArrays[1][i].getUConst());
2880 break;
2881 default:
2882 UNREACHABLE();
2883 break;
2884 }
2885 }
2886 break;
2887 }
2888 case EOpGreaterThanEqualComponentWise:
2889 {
2890 resultArray = new TConstantUnion[maxObjectSize];
2891 for (size_t i = 0; i < maxObjectSize; i++)
2892 {
2893 switch (basicType)
2894 {
2895 case EbtFloat:
2896 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2897 unionArrays[1][i].getFConst());
2898 break;
2899 case EbtInt:
2900 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2901 unionArrays[1][i].getIConst());
2902 break;
2903 case EbtUInt:
2904 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2905 unionArrays[1][i].getUConst());
2906 break;
2907 default:
2908 UNREACHABLE();
2909 break;
2910 }
2911 }
2912 }
2913 break;
2914
2915 case EOpEqualComponentWise:
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 EOpNotEqualComponentWise:
2947 {
2948 resultArray = new TConstantUnion[maxObjectSize];
2949 for (size_t i = 0; i < maxObjectSize; i++)
2950 {
2951 switch (basicType)
2952 {
2953 case EbtFloat:
2954 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2955 unionArrays[1][i].getFConst());
2956 break;
2957 case EbtInt:
2958 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2959 unionArrays[1][i].getIConst());
2960 break;
2961 case EbtUInt:
2962 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2963 unionArrays[1][i].getUConst());
2964 break;
2965 case EbtBool:
2966 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2967 unionArrays[1][i].getBConst());
2968 break;
2969 default:
2970 UNREACHABLE();
2971 break;
2972 }
2973 }
2974 break;
2975 }
2976
2977 case EOpDistance:
2978 {
2979 ASSERT(basicType == EbtFloat);
2980 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2981 resultArray = new TConstantUnion();
2982 for (size_t i = 0; i < maxObjectSize; i++)
2983 {
2984 float x = unionArrays[0][i].getFConst();
2985 float y = unionArrays[1][i].getFConst();
2986 distanceArray[i].setFConst(x - y);
2987 }
2988 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2989 break;
2990 }
2991
2992 case EOpDot:
2993 ASSERT(basicType == EbtFloat);
2994 resultArray = new TConstantUnion();
2995 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2996 break;
2997
2998 case EOpCross:
2999 {
3000 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3001 resultArray = new TConstantUnion[maxObjectSize];
3002 float x0 = unionArrays[0][0].getFConst();
3003 float x1 = unionArrays[0][1].getFConst();
3004 float x2 = unionArrays[0][2].getFConst();
3005 float y0 = unionArrays[1][0].getFConst();
3006 float y1 = unionArrays[1][1].getFConst();
3007 float y2 = unionArrays[1][2].getFConst();
3008 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3009 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3010 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3011 break;
3012 }
3013
3014 case EOpReflect:
3015 {
3016 ASSERT(basicType == EbtFloat);
3017 // genType reflect (genType I, genType N) :
3018 // For the incident vector I and surface orientation N, returns the reflection
3019 // direction:
3020 // I - 2 * dot(N, I) * N.
3021 resultArray = new TConstantUnion[maxObjectSize];
3022 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3023 for (size_t i = 0; i < maxObjectSize; i++)
3024 {
3025 float result = unionArrays[0][i].getFConst() -
3026 2.0f * dotProduct * unionArrays[1][i].getFConst();
3027 resultArray[i].setFConst(result);
3028 }
3029 break;
3030 }
3031
3032 case EOpMulMatrixComponentWise:
3033 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003034 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3035 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003036 // Perform component-wise matrix multiplication.
3037 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003038 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003039 angle::Matrix<float> result =
3040 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3041 SetUnionArrayFromMatrix(result, resultArray);
3042 break;
3043 }
3044
3045 case EOpOuterProduct:
3046 {
3047 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003048 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3049 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003050 resultArray = new TConstantUnion[numRows * numCols];
3051 angle::Matrix<float> result =
3052 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3053 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3054 SetUnionArrayFromMatrix(result, resultArray);
3055 break;
3056 }
3057
3058 case EOpClamp:
3059 {
3060 resultArray = new TConstantUnion[maxObjectSize];
3061 for (size_t i = 0; i < maxObjectSize; i++)
3062 {
3063 switch (basicType)
3064 {
3065 case EbtFloat:
3066 {
3067 float x = unionArrays[0][i].getFConst();
3068 float min = unionArrays[1][i].getFConst();
3069 float max = unionArrays[2][i].getFConst();
3070 // Results are undefined if min > max.
3071 if (min > max)
3072 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3073 &resultArray[i]);
3074 else
3075 resultArray[i].setFConst(gl::clamp(x, min, max));
3076 break;
3077 }
3078
3079 case EbtInt:
3080 {
3081 int x = unionArrays[0][i].getIConst();
3082 int min = unionArrays[1][i].getIConst();
3083 int max = unionArrays[2][i].getIConst();
3084 // Results are undefined if min > max.
3085 if (min > max)
3086 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3087 &resultArray[i]);
3088 else
3089 resultArray[i].setIConst(gl::clamp(x, min, max));
3090 break;
3091 }
3092 case EbtUInt:
3093 {
3094 unsigned int x = unionArrays[0][i].getUConst();
3095 unsigned int min = unionArrays[1][i].getUConst();
3096 unsigned int max = unionArrays[2][i].getUConst();
3097 // Results are undefined if min > max.
3098 if (min > max)
3099 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3100 &resultArray[i]);
3101 else
3102 resultArray[i].setUConst(gl::clamp(x, min, max));
3103 break;
3104 }
3105 default:
3106 UNREACHABLE();
3107 break;
3108 }
3109 }
3110 break;
3111 }
3112
3113 case EOpMix:
3114 {
3115 ASSERT(basicType == EbtFloat);
3116 resultArray = new TConstantUnion[maxObjectSize];
3117 for (size_t i = 0; i < maxObjectSize; i++)
3118 {
3119 float x = unionArrays[0][i].getFConst();
3120 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003121 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003122 if (type == EbtFloat)
3123 {
3124 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3125 float a = unionArrays[2][i].getFConst();
3126 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3127 }
3128 else // 3rd parameter is EbtBool
3129 {
3130 ASSERT(type == EbtBool);
3131 // Selects which vector each returned component comes from.
3132 // For a component of a that is false, the corresponding component of x is
3133 // returned.
3134 // For a component of a that is true, the corresponding component of y is
3135 // returned.
3136 bool a = unionArrays[2][i].getBConst();
3137 resultArray[i].setFConst(a ? y : x);
3138 }
3139 }
3140 break;
3141 }
3142
3143 case EOpSmoothStep:
3144 {
3145 ASSERT(basicType == EbtFloat);
3146 resultArray = new TConstantUnion[maxObjectSize];
3147 for (size_t i = 0; i < maxObjectSize; i++)
3148 {
3149 float edge0 = unionArrays[0][i].getFConst();
3150 float edge1 = unionArrays[1][i].getFConst();
3151 float x = unionArrays[2][i].getFConst();
3152 // Results are undefined if edge0 >= edge1.
3153 if (edge0 >= edge1)
3154 {
3155 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3156 }
3157 else
3158 {
3159 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3160 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3161 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3162 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3163 }
3164 }
3165 break;
3166 }
3167
Olli Etuaho74da73f2017-02-01 15:37:48 +00003168 case EOpLdexp:
3169 {
3170 resultArray = new TConstantUnion[maxObjectSize];
3171 for (size_t i = 0; i < maxObjectSize; i++)
3172 {
3173 float x = unionArrays[0][i].getFConst();
3174 int exp = unionArrays[1][i].getIConst();
3175 if (exp > 128)
3176 {
3177 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3178 }
3179 else
3180 {
3181 resultArray[i].setFConst(gl::Ldexp(x, exp));
3182 }
3183 }
3184 break;
3185 }
3186
Jamie Madille72595b2017-06-06 15:12:26 -04003187 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003188 {
3189 ASSERT(basicType == EbtFloat);
3190 // genType faceforward(genType N, genType I, genType Nref) :
3191 // If dot(Nref, I) < 0 return N, otherwise return -N.
3192 resultArray = new TConstantUnion[maxObjectSize];
3193 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3194 for (size_t i = 0; i < maxObjectSize; i++)
3195 {
3196 if (dotProduct < 0)
3197 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3198 else
3199 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3200 }
3201 break;
3202 }
3203
3204 case EOpRefract:
3205 {
3206 ASSERT(basicType == EbtFloat);
3207 // genType refract(genType I, genType N, float eta) :
3208 // For the incident vector I and surface normal N, and the ratio of indices of
3209 // refraction eta,
3210 // return the refraction vector. The result is computed by
3211 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3212 // if (k < 0.0)
3213 // return genType(0.0)
3214 // else
3215 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3216 resultArray = new TConstantUnion[maxObjectSize];
3217 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3218 for (size_t i = 0; i < maxObjectSize; i++)
3219 {
3220 float eta = unionArrays[2][i].getFConst();
3221 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3222 if (k < 0.0f)
3223 resultArray[i].setFConst(0.0f);
3224 else
3225 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3226 (eta * dotProduct + sqrtf(k)) *
3227 unionArrays[1][i].getFConst());
3228 }
3229 break;
3230 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003231 case EOpBitfieldExtract:
3232 {
3233 resultArray = new TConstantUnion[maxObjectSize];
3234 for (size_t i = 0; i < maxObjectSize; ++i)
3235 {
3236 int offset = unionArrays[1][0].getIConst();
3237 int bits = unionArrays[2][0].getIConst();
3238 if (bits == 0)
3239 {
3240 if (aggregate->getBasicType() == EbtInt)
3241 {
3242 resultArray[i].setIConst(0);
3243 }
3244 else
3245 {
3246 ASSERT(aggregate->getBasicType() == EbtUInt);
3247 resultArray[i].setUConst(0);
3248 }
3249 }
3250 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3251 {
3252 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3253 &resultArray[i]);
3254 }
3255 else
3256 {
3257 // bits can be 32 here, so we need to avoid bit shift overflow.
3258 uint32_t maskMsb = 1u << (bits - 1);
3259 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3260 if (aggregate->getBasicType() == EbtInt)
3261 {
3262 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3263 uint32_t resultUnsigned = (value & mask) >> offset;
3264 if ((resultUnsigned & maskMsb) != 0)
3265 {
3266 // The most significant bits (from bits+1 to the most significant bit)
3267 // should be set to 1.
3268 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3269 resultUnsigned |= higherBitsMask;
3270 }
3271 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3272 }
3273 else
3274 {
3275 ASSERT(aggregate->getBasicType() == EbtUInt);
3276 uint32_t value = unionArrays[0][i].getUConst();
3277 resultArray[i].setUConst((value & mask) >> offset);
3278 }
3279 }
3280 }
3281 break;
3282 }
3283 case EOpBitfieldInsert:
3284 {
3285 resultArray = new TConstantUnion[maxObjectSize];
3286 for (size_t i = 0; i < maxObjectSize; ++i)
3287 {
3288 int offset = unionArrays[2][0].getIConst();
3289 int bits = unionArrays[3][0].getIConst();
3290 if (bits == 0)
3291 {
3292 if (aggregate->getBasicType() == EbtInt)
3293 {
3294 int32_t base = unionArrays[0][i].getIConst();
3295 resultArray[i].setIConst(base);
3296 }
3297 else
3298 {
3299 ASSERT(aggregate->getBasicType() == EbtUInt);
3300 uint32_t base = unionArrays[0][i].getUConst();
3301 resultArray[i].setUConst(base);
3302 }
3303 }
3304 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3305 {
3306 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3307 &resultArray[i]);
3308 }
3309 else
3310 {
3311 // bits can be 32 here, so we need to avoid bit shift overflow.
3312 uint32_t maskMsb = 1u << (bits - 1);
3313 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3314 uint32_t baseMask = ~insertMask;
3315 if (aggregate->getBasicType() == EbtInt)
3316 {
3317 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3318 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3319 uint32_t resultUnsigned =
3320 (base & baseMask) | ((insert << offset) & insertMask);
3321 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3322 }
3323 else
3324 {
3325 ASSERT(aggregate->getBasicType() == EbtUInt);
3326 uint32_t base = unionArrays[0][i].getUConst();
3327 uint32_t insert = unionArrays[1][i].getUConst();
3328 resultArray[i].setUConst((base & baseMask) |
3329 ((insert << offset) & insertMask));
3330 }
3331 }
3332 }
3333 break;
3334 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003335
3336 default:
3337 UNREACHABLE();
3338 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303339 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003340 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303341}
3342
Jamie Madill45bcc782016-11-07 13:58:48 -05003343} // namespace sh