blob: dc6139c862cca5c06e5b1ee00ade2f2884b8ec33 [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 Etuahobed35d72017-12-20 16:36:26 +0200147TName::TName(const TString &name) : mName(name), mIsInternal(false)
Olli Etuahoae4dbf32017-12-08 20:49:00 +0100148{
149}
150
Olli Etuaho1bb85282017-12-14 13:39:53 +0200151TName::TName(const TSymbol *symbol)
Olli Etuahobed35d72017-12-20 16:36:26 +0200152 : mName(symbol->symbolType() == SymbolType::Empty ? "" : symbol->name()),
153 mIsInternal(symbol->symbolType() == SymbolType::AngleInternal)
Olli Etuaho1bb85282017-12-14 13:39:53 +0200154{
155}
156
Jamie Madillb1a85f42014-08-19 15:23:24 -0400157////////////////////////////////////////////////////////////////
158//
159// Member functions of the nodes used for building the tree.
160//
161////////////////////////////////////////////////////////////////
162
Olli Etuahod2a67b92014-10-21 16:42:57 +0300163void TIntermTyped::setTypePreservePrecision(const TType &t)
164{
165 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500166 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300167 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
168 mType.setPrecision(precision);
169}
170
Jamie Madillb1a85f42014-08-19 15:23:24 -0400171#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500172 if (node == original) \
173 { \
174 node = static_cast<type *>(replacement); \
175 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400176 }
177
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500178bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400179{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300180 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400181 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
182 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
183 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100184 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400185 return false;
186}
187
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500188bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400189{
190 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
191 return false;
192}
193
Olli Etuahob6fa0432016-09-28 16:28:05 +0100194bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
195{
196 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
197 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
198 return false;
199}
200
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500201bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400202{
203 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
204 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
205 return false;
206}
207
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500208bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400209{
Olli Etuahoa2234302016-08-31 12:05:39 +0300210 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400211 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
212 return false;
213}
214
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000215bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
216{
217 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
218 return false;
219}
220
Olli Etuaho336b1472016-10-05 16:37:55 +0100221bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
222{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000223 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100224 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
225 return false;
226}
227
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500228bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400229{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100230 return replaceChildNodeInternal(original, replacement);
231}
232
233bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
234{
235 return replaceChildNodeInternal(original, replacement);
236}
237
Olli Etuaho16c745a2017-01-16 17:02:27 +0000238bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
239{
240 return replaceChildNodeInternal(original, replacement);
241}
242
Olli Etuaho13389b62016-10-16 11:48:18 +0100243bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
244{
245 return replaceChildNodeInternal(original, replacement);
246}
247
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100248bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
249{
250 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400251 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100252 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400253 }
254 return false;
255}
256
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100257bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
258 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300259{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100260 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300261 {
262 if (*it == original)
263 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100264 it = getSequence()->erase(it);
265 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300266 return true;
267 }
268 }
269 return false;
270}
271
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100272bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
273 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300274{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100275 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300276 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300277 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300278 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100279 auto it = getSequence()->begin() + position;
280 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300281 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300282}
283
Olli Etuaho195be942017-12-04 23:40:14 +0200284TIntermSymbol::TIntermSymbol(const TVariable *variable)
Olli Etuahobed35d72017-12-20 16:36:26 +0200285 : TIntermTyped(variable->getType()), mVariable(variable), mSymbol(variable)
Olli Etuaho195be942017-12-04 23:40:14 +0200286{
Olli Etuaho195be942017-12-04 23:40:14 +0200287}
288
Olli Etuahob6af22b2017-12-15 14:05:44 +0200289const TSymbolUniqueId &TIntermSymbol::uniqueId() const
290{
291 return mVariable->uniqueId();
292}
293
Olli Etuahofe486322017-03-21 09:30:54 +0000294TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
295 TIntermSequence *arguments)
296{
Olli Etuaho0c371002017-12-13 17:00:25 +0400297 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000298}
299
Olli Etuaho0c371002017-12-13 17:00:25 +0400300TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
301 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000302{
Olli Etuaho0c371002017-12-13 17:00:25 +0400303 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000304}
305
306TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
307 TIntermSequence *arguments)
308{
309 TIntermAggregate *callNode =
Olli Etuaho0c371002017-12-13 17:00:25 +0400310 new TIntermAggregate(&func, func.getReturnType(), EOpCallBuiltInFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000311 // Note that name needs to be set before texture function type is determined.
312 callNode->setBuiltInFunctionPrecision();
313 return callNode;
314}
315
316TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000317 TIntermSequence *arguments)
318{
Olli Etuaho0c371002017-12-13 17:00:25 +0400319 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000320}
321
322TIntermAggregate *TIntermAggregate::Create(const TType &type,
323 TOperator op,
324 TIntermSequence *arguments)
325{
Olli Etuahofe486322017-03-21 09:30:54 +0000326 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400327 ASSERT(op != EOpCallInternalRawFunction); // Should use CreateRawFunctionCall
Olli Etuahofe486322017-03-21 09:30:54 +0000328 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400329 ASSERT(op != EOpConstruct); // Should use CreateConstructor
330 return new TIntermAggregate(nullptr, type, op, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000331}
332
Olli Etuaho0c371002017-12-13 17:00:25 +0400333TIntermAggregate::TIntermAggregate(const TFunction *func,
334 const TType &type,
335 TOperator op,
336 TIntermSequence *arguments)
337 : TIntermOperator(op),
338 mUseEmulatedFunction(false),
339 mGotPrecisionFromChildren(false),
340 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800341{
342 if (arguments != nullptr)
343 {
344 mArguments.swap(*arguments);
345 }
Olli Etuaho1bb85282017-12-14 13:39:53 +0200346 ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800347 setTypePrecisionAndQualifier(type);
348}
349
350void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
351{
352 setType(type);
353 mType.setQualifier(EvqTemporary);
354 if (!isFunctionCall())
355 {
356 if (isConstructor())
357 {
358 // Structs should not be precision qualified, the individual members may be.
359 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300360 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800361 {
362 setPrecisionFromChildren();
363 }
364 }
365 else
366 {
367 setPrecisionForBuiltInOp();
368 }
369 if (areChildrenConstQualified())
370 {
371 mType.setQualifier(EvqConst);
372 }
373 }
374}
375
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200376bool TIntermAggregate::areChildrenConstQualified()
377{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800378 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200379 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800380 TIntermTyped *typedArg = arg->getAsTyped();
381 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200382 {
383 return false;
384 }
385 }
386 return true;
387}
388
Olli Etuahod2a67b92014-10-21 16:42:57 +0300389void TIntermAggregate::setPrecisionFromChildren()
390{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300391 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300392 if (getBasicType() == EbtBool)
393 {
394 mType.setPrecision(EbpUndefined);
395 return;
396 }
397
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500398 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800399 TIntermSequence::iterator childIter = mArguments.begin();
400 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300401 {
402 TIntermTyped *typed = (*childIter)->getAsTyped();
403 if (typed)
404 precision = GetHigherPrecision(typed->getPrecision(), precision);
405 ++childIter;
406 }
407 mType.setPrecision(precision);
408}
409
Olli Etuaho9250cb22017-01-21 10:51:27 +0000410void TIntermAggregate::setPrecisionForBuiltInOp()
411{
412 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800413 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000414 if (!setPrecisionForSpecialBuiltInOp())
415 {
416 setPrecisionFromChildren();
417 }
418}
419
420bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
421{
422 switch (mOp)
423 {
424 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800425 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
426 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000427 return true;
428 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800429 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
430 mArguments[1]->getAsTyped()->getPrecision()));
431 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000432 return true;
433 case EOpUaddCarry:
434 case EOpUsubBorrow:
435 mType.setPrecision(EbpHigh);
436 return true;
437 default:
438 return false;
439 }
440}
441
Olli Etuahod2a67b92014-10-21 16:42:57 +0300442void TIntermAggregate::setBuiltInFunctionPrecision()
443{
444 // All built-ins returning bool should be handled as ops, not functions.
445 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800446 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300447
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800448 TPrecision precision = EbpUndefined;
449 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300450 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800451 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300452 // ESSL spec section 8: texture functions get their precision from the sampler.
453 if (typed && IsSampler(typed->getBasicType()))
454 {
455 precision = typed->getPrecision();
456 break;
457 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300458 }
459 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
460 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuahobed35d72017-12-20 16:36:26 +0200461 if (mFunction->name().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300462 mType.setPrecision(EbpHigh);
463 else
464 mType.setPrecision(precision);
465}
466
Olli Etuahof2209f72017-04-01 12:45:55 +0300467TString TIntermAggregate::getSymbolTableMangledName() const
468{
469 ASSERT(!isConstructor());
470 switch (mOp)
471 {
472 case EOpCallInternalRawFunction:
473 case EOpCallBuiltInFunction:
474 case EOpCallFunctionInAST:
Olli Etuahobed35d72017-12-20 16:36:26 +0200475 return TFunction::GetMangledNameFromCall(mFunction->name(), mArguments);
Olli Etuahof2209f72017-04-01 12:45:55 +0300476 default:
477 TString opString = GetOperatorString(mOp);
478 return TFunction::GetMangledNameFromCall(opString, mArguments);
479 }
480}
481
Olli Etuaho0c371002017-12-13 17:00:25 +0400482const char *TIntermAggregate::functionName() const
483{
484 ASSERT(!isConstructor());
485 switch (mOp)
486 {
487 case EOpCallInternalRawFunction:
488 case EOpCallBuiltInFunction:
489 case EOpCallFunctionInAST:
Olli Etuahobed35d72017-12-20 16:36:26 +0200490 return mFunction->name().c_str();
Olli Etuaho0c371002017-12-13 17:00:25 +0400491 default:
492 return GetOperatorString(mOp);
493 }
494}
495
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300496bool TIntermAggregate::hasSideEffects() const
497{
Olli Etuaho0c371002017-12-13 17:00:25 +0400498 if (isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300499 {
500 for (TIntermNode *arg : mArguments)
501 {
502 if (arg->getAsTyped()->hasSideEffects())
503 {
504 return true;
505 }
506 }
507 return false;
508 }
509 // Conservatively assume most aggregate operators have side-effects
510 return true;
511}
512
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100513void TIntermBlock::appendStatement(TIntermNode *statement)
514{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300515 // Declaration nodes with no children can appear if it was an empty declaration or if all the
516 // declarators just added constants to the symbol table instead of generating code. We still
517 // need to add the declaration to the AST in that case because it might be relevant to the
518 // validity of switch/case.
519 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100520 {
521 mStatements.push_back(statement);
522 }
523}
524
Olli Etuaho16c745a2017-01-16 17:02:27 +0000525void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
526{
527 ASSERT(parameter != nullptr);
528 mParameters.push_back(parameter);
529}
530
Olli Etuaho13389b62016-10-16 11:48:18 +0100531void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
532{
533 ASSERT(declarator != nullptr);
534 ASSERT(declarator->getAsSymbolNode() != nullptr ||
535 (declarator->getAsBinaryNode() != nullptr &&
536 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
537 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300538 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100539 mDeclarators.push_back(declarator);
540}
541
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300542bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
543{
544 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
545 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
546 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
547 return false;
548}
549
Olli Etuaho57961272016-09-14 13:57:46 +0300550bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400551{
552 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100553 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
554 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400555 return false;
556}
557
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500558bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200559{
560 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100561 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300562 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200563 return false;
564}
565
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500566bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200567{
568 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
569 return false;
570}
571
Olli Etuahod7a25242015-08-18 13:49:45 +0300572TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
573{
574 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
575 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
576 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
577 mLine = node.mLine;
578}
579
Olli Etuahod4f4c112016-04-15 15:11:24 +0300580bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
581{
582 TIntermAggregate *constructor = getAsAggregate();
583 if (!constructor || !constructor->isConstructor())
584 {
585 return false;
586 }
587 for (TIntermNode *&node : *constructor->getSequence())
588 {
589 if (!node->getAsConstantUnion())
590 return false;
591 }
592 return true;
593}
594
Olli Etuahod7a25242015-08-18 13:49:45 +0300595TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
596{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200597 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300598}
599
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200600TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
601 : TIntermTyped(function->getReturnType()), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100602{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200603 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100604}
605
Olli Etuahod7a25242015-08-18 13:49:45 +0300606TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
607 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300608 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100609 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400610 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300611{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800612 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300613 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800614 TIntermTyped *typedArg = arg->getAsTyped();
615 ASSERT(typedArg != nullptr);
616 TIntermTyped *argCopy = typedArg->deepCopy();
617 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300618 }
619}
620
Olli Etuahofe486322017-03-21 09:30:54 +0000621TIntermAggregate *TIntermAggregate::shallowCopy() const
622{
623 TIntermSequence *copySeq = new TIntermSequence();
624 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400625 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000626 copyNode->setLine(mLine);
627 return copyNode;
628}
629
Olli Etuahob6fa0432016-09-28 16:28:05 +0100630TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
631{
632 TIntermTyped *operandCopy = node.mOperand->deepCopy();
633 ASSERT(operandCopy != nullptr);
634 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000635 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100636}
637
Olli Etuahod7a25242015-08-18 13:49:45 +0300638TIntermBinary::TIntermBinary(const TIntermBinary &node)
639 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
640{
641 TIntermTyped *leftCopy = node.mLeft->deepCopy();
642 TIntermTyped *rightCopy = node.mRight->deepCopy();
643 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
644 mLeft = leftCopy;
645 mRight = rightCopy;
646}
647
648TIntermUnary::TIntermUnary(const TIntermUnary &node)
649 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
650{
651 TIntermTyped *operandCopy = node.mOperand->deepCopy();
652 ASSERT(operandCopy != nullptr);
653 mOperand = operandCopy;
654}
655
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300656TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300657{
Olli Etuahod7a25242015-08-18 13:49:45 +0300658 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300659 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
660 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300661 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300662 mCondition = conditionCopy;
663 mTrueExpression = trueCopy;
664 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300665}
666
Jamie Madillb1a85f42014-08-19 15:23:24 -0400667bool TIntermOperator::isAssignment() const
668{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300669 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400670}
671
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300672bool TIntermOperator::isMultiplication() const
673{
674 switch (mOp)
675 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500676 case EOpMul:
677 case EOpMatrixTimesMatrix:
678 case EOpMatrixTimesVector:
679 case EOpMatrixTimesScalar:
680 case EOpVectorTimesMatrix:
681 case EOpVectorTimesScalar:
682 return true;
683 default:
684 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300685 }
686}
687
Jamie Madillb1a85f42014-08-19 15:23:24 -0400688bool TIntermOperator::isConstructor() const
689{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300690 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400691}
692
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800693bool TIntermOperator::isFunctionCall() const
694{
695 switch (mOp)
696 {
697 case EOpCallFunctionInAST:
698 case EOpCallBuiltInFunction:
699 case EOpCallInternalRawFunction:
700 return true;
701 default:
702 return false;
703 }
704}
705
Olli Etuaho1dded802016-08-18 18:13:13 +0300706TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
707{
708 if (left.isMatrix())
709 {
710 if (right.isMatrix())
711 {
712 return EOpMatrixTimesMatrix;
713 }
714 else
715 {
716 if (right.isVector())
717 {
718 return EOpMatrixTimesVector;
719 }
720 else
721 {
722 return EOpMatrixTimesScalar;
723 }
724 }
725 }
726 else
727 {
728 if (right.isMatrix())
729 {
730 if (left.isVector())
731 {
732 return EOpVectorTimesMatrix;
733 }
734 else
735 {
736 return EOpMatrixTimesScalar;
737 }
738 }
739 else
740 {
741 // Neither operand is a matrix.
742 if (left.isVector() == right.isVector())
743 {
744 // Leave as component product.
745 return EOpMul;
746 }
747 else
748 {
749 return EOpVectorTimesScalar;
750 }
751 }
752 }
753}
754
755TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
756{
757 if (left.isMatrix())
758 {
759 if (right.isMatrix())
760 {
761 return EOpMatrixTimesMatrixAssign;
762 }
763 else
764 {
765 // right should be scalar, but this may not be validated yet.
766 return EOpMatrixTimesScalarAssign;
767 }
768 }
769 else
770 {
771 if (right.isMatrix())
772 {
773 // Left should be a vector, but this may not be validated yet.
774 return EOpVectorTimesMatrixAssign;
775 }
776 else
777 {
778 // Neither operand is a matrix.
779 if (left.isVector() == right.isVector())
780 {
781 // Leave as component product.
782 return EOpMulAssign;
783 }
784 else
785 {
786 // left should be vector and right should be scalar, but this may not be validated
787 // yet.
788 return EOpVectorTimesScalarAssign;
789 }
790 }
791 }
792}
793
Jamie Madillb1a85f42014-08-19 15:23:24 -0400794//
795// Make sure the type of a unary operator is appropriate for its
796// combination of operation and operand type.
797//
Olli Etuahoa2234302016-08-31 12:05:39 +0300798void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400799{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300800 if (mOp == EOpArrayLength)
801 {
802 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
803 setType(TType(EbtInt, EbpUndefined, EvqConst));
804 return;
805 }
806
Olli Etuahoa2234302016-08-31 12:05:39 +0300807 TQualifier resultQualifier = EvqTemporary;
808 if (mOperand->getQualifier() == EvqConst)
809 resultQualifier = EvqConst;
810
811 unsigned char operandPrimarySize =
812 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400813 switch (mOp)
814 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300815 case EOpFloatBitsToInt:
816 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
817 break;
818 case EOpFloatBitsToUint:
819 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
820 break;
821 case EOpIntBitsToFloat:
822 case EOpUintBitsToFloat:
823 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
824 break;
825 case EOpPackSnorm2x16:
826 case EOpPackUnorm2x16:
827 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800828 case EOpPackUnorm4x8:
829 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300830 setType(TType(EbtUInt, EbpHigh, resultQualifier));
831 break;
832 case EOpUnpackSnorm2x16:
833 case EOpUnpackUnorm2x16:
834 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
835 break;
836 case EOpUnpackHalf2x16:
837 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
838 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800839 case EOpUnpackUnorm4x8:
840 case EOpUnpackSnorm4x8:
841 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
842 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300843 case EOpAny:
844 case EOpAll:
845 setType(TType(EbtBool, EbpUndefined, resultQualifier));
846 break;
847 case EOpLength:
848 case EOpDeterminant:
849 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
850 break;
851 case EOpTranspose:
852 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
853 static_cast<unsigned char>(mOperand->getType().getRows()),
854 static_cast<unsigned char>(mOperand->getType().getCols())));
855 break;
856 case EOpIsInf:
857 case EOpIsNan:
858 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
859 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000860 case EOpBitfieldReverse:
861 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
862 break;
863 case EOpBitCount:
864 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
865 break;
866 case EOpFindLSB:
867 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
868 break;
869 case EOpFindMSB:
870 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
871 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300872 default:
873 setType(mOperand->getType());
874 mType.setQualifier(resultQualifier);
875 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400876 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300877}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400878
Olli Etuahob6fa0432016-09-28 16:28:05 +0100879TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
880 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
881 mOperand(operand),
882 mSwizzleOffsets(swizzleOffsets)
883{
884 ASSERT(mSwizzleOffsets.size() <= 4);
885 promote();
886}
887
Olli Etuahoa2234302016-08-31 12:05:39 +0300888TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
889 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
890{
891 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400892}
893
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300894TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
895 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
896{
897 promote();
898}
899
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000900TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
901 : TIntermNode(), mSymbol(symbol)
902{
903 ASSERT(symbol);
904 setLine(line);
905}
906
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300907TIntermTernary::TIntermTernary(TIntermTyped *cond,
908 TIntermTyped *trueExpression,
909 TIntermTyped *falseExpression)
910 : TIntermTyped(trueExpression->getType()),
911 mCondition(cond),
912 mTrueExpression(trueExpression),
913 mFalseExpression(falseExpression)
914{
915 getTypePointer()->setQualifier(
916 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
917}
918
Olli Etuaho81629262017-04-19 11:56:01 +0300919TIntermLoop::TIntermLoop(TLoopType type,
920 TIntermNode *init,
921 TIntermTyped *cond,
922 TIntermTyped *expr,
923 TIntermBlock *body)
924 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
925{
926 // Declaration nodes with no children can appear if all the declarators just added constants to
927 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
928 if (mInit && mInit->getAsDeclarationNode() &&
929 mInit->getAsDeclarationNode()->getSequence()->empty())
930 {
931 mInit = nullptr;
932 }
933}
934
Olli Etuaho923ecef2017-10-11 12:01:38 +0300935TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
936 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
937{
938 // Prune empty false blocks so that there won't be unnecessary operations done on it.
939 if (mFalseBlock && mFalseBlock->getSequence()->empty())
940 {
941 mFalseBlock = nullptr;
942 }
943}
944
945TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
946 : TIntermNode(), mInit(init), mStatementList(statementList)
947{
948 ASSERT(mStatementList);
949}
950
951void TIntermSwitch::setStatementList(TIntermBlock *statementList)
952{
953 ASSERT(statementList);
954 mStatementList = statementList;
955}
956
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300957// static
958TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
959 TIntermTyped *trueExpression,
960 TIntermTyped *falseExpression)
961{
962 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
963 falseExpression->getQualifier() == EvqConst)
964 {
965 return EvqConst;
966 }
967 return EvqTemporary;
968}
969
Olli Etuahoeb7f90f2017-07-07 17:25:23 +0300970TIntermTyped *TIntermTernary::fold()
971{
972 if (mCondition->getAsConstantUnion())
973 {
974 if (mCondition->getAsConstantUnion()->getBConst(0))
975 {
976 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
977 return mTrueExpression;
978 }
979 else
980 {
981 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
982 return mFalseExpression;
983 }
984 }
985 return this;
986}
987
Olli Etuahob6fa0432016-09-28 16:28:05 +0100988void TIntermSwizzle::promote()
989{
990 TQualifier resultQualifier = EvqTemporary;
991 if (mOperand->getQualifier() == EvqConst)
992 resultQualifier = EvqConst;
993
994 auto numFields = mSwizzleOffsets.size();
995 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
996 static_cast<unsigned char>(numFields)));
997}
998
999bool TIntermSwizzle::hasDuplicateOffsets() const
1000{
1001 int offsetCount[4] = {0u, 0u, 0u, 0u};
1002 for (const auto offset : mSwizzleOffsets)
1003 {
1004 offsetCount[offset]++;
1005 if (offsetCount[offset] > 1)
1006 {
1007 return true;
1008 }
1009 }
1010 return false;
1011}
1012
Olli Etuaho09b04a22016-12-15 13:30:26 +00001013bool TIntermSwizzle::offsetsMatch(int offset) const
1014{
1015 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1016}
1017
Olli Etuahob6fa0432016-09-28 16:28:05 +01001018void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1019{
1020 for (const int offset : mSwizzleOffsets)
1021 {
1022 switch (offset)
1023 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001024 case 0:
1025 *out << "x";
1026 break;
1027 case 1:
1028 *out << "y";
1029 break;
1030 case 2:
1031 *out << "z";
1032 break;
1033 case 3:
1034 *out << "w";
1035 break;
1036 default:
1037 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001038 }
1039 }
1040}
1041
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001042TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1043 const TIntermTyped *left,
1044 const TIntermTyped *right)
1045{
1046 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1047 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1048 right->getQualifier() != EvqConst)
1049 {
1050 return EvqTemporary;
1051 }
1052 return EvqConst;
1053}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001054
1055// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001056void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001057{
Olli Etuaho1dded802016-08-18 18:13:13 +03001058 ASSERT(!isMultiplication() ||
1059 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1060
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001061 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1062 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001063 if (mOp == EOpComma)
1064 {
1065 setType(mRight->getType());
1066 return;
1067 }
1068
Jamie Madillb1a85f42014-08-19 15:23:24 -04001069 // Base assumption: just make the type the same as the left
1070 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001071 setType(mLeft->getType());
1072
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001073 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001074 // Binary operations results in temporary variables unless both
1075 // operands are const.
1076 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1077 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001078 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001079 getTypePointer()->setQualifier(EvqTemporary);
1080 }
1081
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001082 // Handle indexing ops.
1083 switch (mOp)
1084 {
1085 case EOpIndexDirect:
1086 case EOpIndexIndirect:
1087 if (mLeft->isArray())
1088 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001089 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001090 }
1091 else if (mLeft->isMatrix())
1092 {
1093 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1094 static_cast<unsigned char>(mLeft->getRows())));
1095 }
1096 else if (mLeft->isVector())
1097 {
1098 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1099 }
1100 else
1101 {
1102 UNREACHABLE();
1103 }
1104 return;
1105 case EOpIndexDirectStruct:
1106 {
1107 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1108 const int i = mRight->getAsConstantUnion()->getIConst(0);
1109 setType(*fields[i]->type());
1110 getTypePointer()->setQualifier(resultQualifier);
1111 return;
1112 }
1113 case EOpIndexDirectInterfaceBlock:
1114 {
1115 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1116 const int i = mRight->getAsConstantUnion()->getIConst(0);
1117 setType(*fields[i]->type());
1118 getTypePointer()->setQualifier(resultQualifier);
1119 return;
1120 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001121 default:
1122 break;
1123 }
1124
1125 ASSERT(mLeft->isArray() == mRight->isArray());
1126
1127 // The result gets promoted to the highest precision.
1128 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1129 getTypePointer()->setPrecision(higherPrecision);
1130
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001131 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001132
1133 //
1134 // All scalars or structs. Code after this test assumes this case is removed!
1135 //
1136 if (nominalSize == 1)
1137 {
1138 switch (mOp)
1139 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001140 //
1141 // Promote to conditional
1142 //
1143 case EOpEqual:
1144 case EOpNotEqual:
1145 case EOpLessThan:
1146 case EOpGreaterThan:
1147 case EOpLessThanEqual:
1148 case EOpGreaterThanEqual:
1149 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1150 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001151
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001152 //
1153 // And and Or operate on conditionals
1154 //
1155 case EOpLogicalAnd:
1156 case EOpLogicalXor:
1157 case EOpLogicalOr:
1158 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1159 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1160 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001161
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001162 default:
1163 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001164 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001165 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001166 }
1167
1168 // If we reach here, at least one of the operands is vector or matrix.
1169 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001170 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001171
Jamie Madillb1a85f42014-08-19 15:23:24 -04001172 switch (mOp)
1173 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001174 case EOpMul:
1175 break;
1176 case EOpMatrixTimesScalar:
1177 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001178 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001179 setType(TType(basicType, higherPrecision, resultQualifier,
1180 static_cast<unsigned char>(mRight->getCols()),
1181 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001182 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001183 break;
1184 case EOpMatrixTimesVector:
1185 setType(TType(basicType, higherPrecision, resultQualifier,
1186 static_cast<unsigned char>(mLeft->getRows()), 1));
1187 break;
1188 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001189 setType(TType(basicType, higherPrecision, resultQualifier,
1190 static_cast<unsigned char>(mRight->getCols()),
1191 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001192 break;
1193 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001194 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001195 static_cast<unsigned char>(nominalSize), 1));
1196 break;
1197 case EOpVectorTimesMatrix:
1198 setType(TType(basicType, higherPrecision, resultQualifier,
1199 static_cast<unsigned char>(mRight->getCols()), 1));
1200 break;
1201 case EOpMulAssign:
1202 case EOpVectorTimesScalarAssign:
1203 case EOpVectorTimesMatrixAssign:
1204 case EOpMatrixTimesScalarAssign:
1205 case EOpMatrixTimesMatrixAssign:
1206 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1207 break;
1208 case EOpAssign:
1209 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001210 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1211 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1212 break;
1213 case EOpAdd:
1214 case EOpSub:
1215 case EOpDiv:
1216 case EOpIMod:
1217 case EOpBitShiftLeft:
1218 case EOpBitShiftRight:
1219 case EOpBitwiseAnd:
1220 case EOpBitwiseXor:
1221 case EOpBitwiseOr:
1222 case EOpAddAssign:
1223 case EOpSubAssign:
1224 case EOpDivAssign:
1225 case EOpIModAssign:
1226 case EOpBitShiftLeftAssign:
1227 case EOpBitShiftRightAssign:
1228 case EOpBitwiseAndAssign:
1229 case EOpBitwiseXorAssign:
1230 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001231 {
1232 const int secondarySize =
1233 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1234 setType(TType(basicType, higherPrecision, resultQualifier,
1235 static_cast<unsigned char>(nominalSize),
1236 static_cast<unsigned char>(secondarySize)));
1237 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001238 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001239 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001240 case EOpEqual:
1241 case EOpNotEqual:
1242 case EOpLessThan:
1243 case EOpGreaterThan:
1244 case EOpLessThanEqual:
1245 case EOpGreaterThanEqual:
1246 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1247 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001248 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001249 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001250
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001251 case EOpIndexDirect:
1252 case EOpIndexIndirect:
1253 case EOpIndexDirectInterfaceBlock:
1254 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001255 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001256 UNREACHABLE();
1257 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001258 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001259 UNREACHABLE();
1260 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001261 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001262}
1263
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001264const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001265{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001266 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001267 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001268 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001269 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001270 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001271 size_t arrayElementSize = arrayElementType.getObjectSize();
1272 return &mUnionArrayPointer[arrayElementSize * index];
1273 }
1274 else if (isMatrix())
1275 {
1276 ASSERT(index < getType().getCols());
1277 int size = getType().getRows();
1278 return &mUnionArrayPointer[size * index];
1279 }
1280 else if (isVector())
1281 {
1282 ASSERT(index < getType().getNominalSize());
1283 return &mUnionArrayPointer[index];
1284 }
1285 else
1286 {
1287 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001288 return nullptr;
1289 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001290}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001291
Olli Etuahob6fa0432016-09-28 16:28:05 +01001292TIntermTyped *TIntermSwizzle::fold()
1293{
1294 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1295 if (operandConstant == nullptr)
1296 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001297 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001298 }
1299
1300 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1301 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1302 {
1303 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1304 }
1305 return CreateFoldedNode(constArray, this, mType.getQualifier());
1306}
1307
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001308TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1309{
1310 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1311 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1312 switch (mOp)
1313 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001314 case EOpComma:
1315 {
1316 if (mLeft->hasSideEffects())
1317 {
1318 return this;
1319 }
1320 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1321 return mRight;
1322 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001323 case EOpIndexDirect:
1324 {
1325 if (leftConstant == nullptr || rightConstant == nullptr)
1326 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001327 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001328 }
1329 int index = rightConstant->getIConst(0);
1330
1331 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001332 if (!constArray)
1333 {
1334 return this;
1335 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001336 return CreateFoldedNode(constArray, this, mType.getQualifier());
1337 }
1338 case EOpIndexDirectStruct:
1339 {
1340 if (leftConstant == nullptr || rightConstant == nullptr)
1341 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001342 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001343 }
1344 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1345 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1346
1347 size_t previousFieldsSize = 0;
1348 for (size_t i = 0; i < index; ++i)
1349 {
1350 previousFieldsSize += fields[i]->type()->getObjectSize();
1351 }
1352
1353 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1354 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1355 }
1356 case EOpIndexIndirect:
1357 case EOpIndexDirectInterfaceBlock:
1358 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001359 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001360 default:
1361 {
1362 if (leftConstant == nullptr || rightConstant == nullptr)
1363 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001364 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001365 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001366 TConstantUnion *constArray =
1367 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001368 if (!constArray)
1369 {
1370 return this;
1371 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001372
1373 // Nodes may be constant folded without being qualified as constant.
1374 return CreateFoldedNode(constArray, this, mType.getQualifier());
1375 }
1376 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001377}
1378
Olli Etuahof119a262016-08-19 15:54:22 +03001379TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001380{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301381 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001382
1383 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301384 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001385 // The size of runtime-sized arrays may only be determined at runtime.
1386 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001387 {
1388 return this;
1389 }
1390 constArray = new TConstantUnion[1];
1391 constArray->setIConst(mOperand->getOutermostArraySize());
1392 }
1393 else
1394 {
1395 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1396 if (operandConstant == nullptr)
1397 {
1398 return this;
1399 }
1400
1401 switch (mOp)
1402 {
1403 case EOpAny:
1404 case EOpAll:
1405 case EOpLength:
1406 case EOpTranspose:
1407 case EOpDeterminant:
1408 case EOpInverse:
1409 case EOpPackSnorm2x16:
1410 case EOpUnpackSnorm2x16:
1411 case EOpPackUnorm2x16:
1412 case EOpUnpackUnorm2x16:
1413 case EOpPackHalf2x16:
1414 case EOpUnpackHalf2x16:
1415 case EOpPackUnorm4x8:
1416 case EOpPackSnorm4x8:
1417 case EOpUnpackUnorm4x8:
1418 case EOpUnpackSnorm4x8:
1419 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1420 break;
1421 default:
1422 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1423 break;
1424 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301425 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001426 if (constArray == nullptr)
1427 {
1428 return this;
1429 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001430
1431 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001432 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001433}
1434
Olli Etuahof119a262016-08-19 15:54:22 +03001435TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001436{
1437 // Make sure that all params are constant before actual constant folding.
1438 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001439 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001440 if (param->getAsConstantUnion() == nullptr)
1441 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001442 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001443 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001444 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001445 TConstantUnion *constArray = nullptr;
1446 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001447 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001448 else
Olli Etuahof119a262016-08-19 15:54:22 +03001449 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001450
1451 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001452 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001453}
1454
Jamie Madillb1a85f42014-08-19 15:23:24 -04001455//
1456// The fold functions see if an operation on a constant can be done in place,
1457// without generating run-time code.
1458//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001459// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001460//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001461TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1462 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001463 TDiagnostics *diagnostics,
1464 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001465{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001466 const TConstantUnion *leftArray = getUnionArrayPointer();
1467 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001468
Olli Etuahof119a262016-08-19 15:54:22 +03001469 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001470
1471 size_t objectSize = getType().getObjectSize();
1472
1473 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1474 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1475 {
1476 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1477 }
1478 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1479 {
1480 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001481 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001482 objectSize = rightNode->getType().getObjectSize();
1483 }
1484
1485 TConstantUnion *resultArray = nullptr;
1486
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001487 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001488 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001489 case EOpAdd:
1490 resultArray = new TConstantUnion[objectSize];
1491 for (size_t i = 0; i < objectSize; i++)
1492 resultArray[i] =
1493 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1494 break;
1495 case EOpSub:
1496 resultArray = new TConstantUnion[objectSize];
1497 for (size_t i = 0; i < objectSize; i++)
1498 resultArray[i] =
1499 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1500 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001501
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001502 case EOpMul:
1503 case EOpVectorTimesScalar:
1504 case EOpMatrixTimesScalar:
1505 resultArray = new TConstantUnion[objectSize];
1506 for (size_t i = 0; i < objectSize; i++)
1507 resultArray[i] =
1508 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1509 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001510
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001511 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001512 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001513 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001514 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001515
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001516 const int leftCols = getCols();
1517 const int leftRows = getRows();
1518 const int rightCols = rightNode->getType().getCols();
1519 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001520 const int resultCols = rightCols;
1521 const int resultRows = leftRows;
1522
1523 resultArray = new TConstantUnion[resultCols * resultRows];
1524 for (int row = 0; row < resultRows; row++)
1525 {
1526 for (int column = 0; column < resultCols; column++)
1527 {
1528 resultArray[resultRows * column + row].setFConst(0.0f);
1529 for (int i = 0; i < leftCols; i++)
1530 {
1531 resultArray[resultRows * column + row].setFConst(
1532 resultArray[resultRows * column + row].getFConst() +
1533 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001534 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001535 }
1536 }
1537 }
1538 }
1539 break;
1540
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001541 case EOpDiv:
1542 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001543 {
1544 resultArray = new TConstantUnion[objectSize];
1545 for (size_t i = 0; i < objectSize; i++)
1546 {
1547 switch (getType().getBasicType())
1548 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001549 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001550 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001551 ASSERT(op == EOpDiv);
1552 float dividend = leftArray[i].getFConst();
1553 float divisor = rightArray[i].getFConst();
1554 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001555 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001556 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001557 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001558 diagnostics->warning(
1559 getLine(),
1560 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001561 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001562 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001563 }
1564 else
1565 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001566 diagnostics->warning(getLine(),
1567 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001568 bool negativeResult =
1569 std::signbit(dividend) != std::signbit(divisor);
1570 resultArray[i].setFConst(
1571 negativeResult ? -std::numeric_limits<float>::infinity()
1572 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001573 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001574 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001575 else if (gl::isInf(dividend) && gl::isInf(divisor))
1576 {
1577 diagnostics->warning(getLine(),
1578 "Infinity divided by infinity during constant "
1579 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001580 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001581 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1582 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001583 else
1584 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001585 float result = dividend / divisor;
1586 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001587 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001588 diagnostics->warning(
1589 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001590 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001591 }
1592 resultArray[i].setFConst(result);
1593 }
1594 break;
1595 }
1596 case EbtInt:
1597 if (rightArray[i] == 0)
1598 {
1599 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001600 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001601 resultArray[i].setIConst(INT_MAX);
1602 }
1603 else
1604 {
1605 int lhs = leftArray[i].getIConst();
1606 int divisor = rightArray[i].getIConst();
1607 if (op == EOpDiv)
1608 {
1609 // Check for the special case where the minimum representable number
1610 // is
1611 // divided by -1. If left alone this leads to integer overflow in
1612 // C++.
1613 // ESSL 3.00.6 section 4.1.3 Integers:
1614 // "However, for the case where the minimum representable value is
1615 // divided by -1, it is allowed to return either the minimum
1616 // representable value or the maximum representable value."
1617 if (lhs == -0x7fffffff - 1 && divisor == -1)
1618 {
1619 resultArray[i].setIConst(0x7fffffff);
1620 }
1621 else
1622 {
1623 resultArray[i].setIConst(lhs / divisor);
1624 }
Olli Etuahod4453572016-09-27 13:21:46 +01001625 }
1626 else
1627 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001628 ASSERT(op == EOpIMod);
1629 if (lhs < 0 || divisor < 0)
1630 {
1631 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1632 // when
1633 // either one of the operands is negative.
1634 diagnostics->warning(getLine(),
1635 "Negative modulus operator operand "
1636 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001637 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001638 resultArray[i].setIConst(0);
1639 }
1640 else
1641 {
1642 resultArray[i].setIConst(lhs % divisor);
1643 }
Olli Etuahod4453572016-09-27 13:21:46 +01001644 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001645 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001646 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001647
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001648 case EbtUInt:
1649 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001650 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001651 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001652 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001653 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001654 }
1655 else
1656 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001657 if (op == EOpDiv)
1658 {
1659 resultArray[i].setUConst(leftArray[i].getUConst() /
1660 rightArray[i].getUConst());
1661 }
1662 else
1663 {
1664 ASSERT(op == EOpIMod);
1665 resultArray[i].setUConst(leftArray[i].getUConst() %
1666 rightArray[i].getUConst());
1667 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001668 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001669 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001670
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001671 default:
1672 UNREACHABLE();
1673 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001674 }
1675 }
1676 }
1677 break;
1678
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001679 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001680 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001681 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001682 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001683
1684 const int matrixCols = getCols();
1685 const int matrixRows = getRows();
1686
1687 resultArray = new TConstantUnion[matrixRows];
1688
1689 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1690 {
1691 resultArray[matrixRow].setFConst(0.0f);
1692 for (int col = 0; col < matrixCols; col++)
1693 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001694 resultArray[matrixRow].setFConst(
1695 resultArray[matrixRow].getFConst() +
1696 leftArray[col * matrixRows + matrixRow].getFConst() *
1697 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001698 }
1699 }
1700 }
1701 break;
1702
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001703 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001704 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001705 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001706 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001707
1708 const int matrixCols = rightNode->getType().getCols();
1709 const int matrixRows = rightNode->getType().getRows();
1710
1711 resultArray = new TConstantUnion[matrixCols];
1712
1713 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1714 {
1715 resultArray[matrixCol].setFConst(0.0f);
1716 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1717 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001718 resultArray[matrixCol].setFConst(
1719 resultArray[matrixCol].getFConst() +
1720 leftArray[matrixRow].getFConst() *
1721 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001722 }
1723 }
1724 }
1725 break;
1726
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001727 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001728 {
1729 resultArray = new TConstantUnion[objectSize];
1730 for (size_t i = 0; i < objectSize; i++)
1731 {
1732 resultArray[i] = leftArray[i] && rightArray[i];
1733 }
1734 }
1735 break;
1736
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001737 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001738 {
1739 resultArray = new TConstantUnion[objectSize];
1740 for (size_t i = 0; i < objectSize; i++)
1741 {
1742 resultArray[i] = leftArray[i] || rightArray[i];
1743 }
1744 }
1745 break;
1746
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001747 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001748 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001749 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001750 resultArray = new TConstantUnion[objectSize];
1751 for (size_t i = 0; i < objectSize; i++)
1752 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001753 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001754 }
1755 }
1756 break;
1757
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001758 case EOpBitwiseAnd:
1759 resultArray = new TConstantUnion[objectSize];
1760 for (size_t i = 0; i < objectSize; i++)
1761 resultArray[i] = leftArray[i] & rightArray[i];
1762 break;
1763 case EOpBitwiseXor:
1764 resultArray = new TConstantUnion[objectSize];
1765 for (size_t i = 0; i < objectSize; i++)
1766 resultArray[i] = leftArray[i] ^ rightArray[i];
1767 break;
1768 case EOpBitwiseOr:
1769 resultArray = new TConstantUnion[objectSize];
1770 for (size_t i = 0; i < objectSize; i++)
1771 resultArray[i] = leftArray[i] | rightArray[i];
1772 break;
1773 case EOpBitShiftLeft:
1774 resultArray = new TConstantUnion[objectSize];
1775 for (size_t i = 0; i < objectSize; i++)
1776 resultArray[i] =
1777 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1778 break;
1779 case EOpBitShiftRight:
1780 resultArray = new TConstantUnion[objectSize];
1781 for (size_t i = 0; i < objectSize; i++)
1782 resultArray[i] =
1783 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1784 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001785
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001786 case EOpLessThan:
1787 ASSERT(objectSize == 1);
1788 resultArray = new TConstantUnion[1];
1789 resultArray->setBConst(*leftArray < *rightArray);
1790 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001791
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001792 case EOpGreaterThan:
1793 ASSERT(objectSize == 1);
1794 resultArray = new TConstantUnion[1];
1795 resultArray->setBConst(*leftArray > *rightArray);
1796 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001797
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001798 case EOpLessThanEqual:
1799 ASSERT(objectSize == 1);
1800 resultArray = new TConstantUnion[1];
1801 resultArray->setBConst(!(*leftArray > *rightArray));
1802 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001803
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001804 case EOpGreaterThanEqual:
1805 ASSERT(objectSize == 1);
1806 resultArray = new TConstantUnion[1];
1807 resultArray->setBConst(!(*leftArray < *rightArray));
1808 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001809
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001810 case EOpEqual:
1811 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001812 {
1813 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001814 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001815 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001816 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001817 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001818 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001819 equal = false;
1820 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001821 }
1822 }
1823 if (op == EOpEqual)
1824 {
1825 resultArray->setBConst(equal);
1826 }
1827 else
1828 {
1829 resultArray->setBConst(!equal);
1830 }
1831 }
1832 break;
1833
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001834 default:
1835 UNREACHABLE();
1836 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001837 }
1838 return resultArray;
1839}
1840
Olli Etuahof119a262016-08-19 15:54:22 +03001841// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1842// code. Returns the constant value to keep using. Nullptr should not be returned.
1843TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001844{
Olli Etuahof119a262016-08-19 15:54:22 +03001845 // Do operations where the return type may have a different number of components compared to the
1846 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001847
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001848 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001849 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301850
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001851 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301852 TConstantUnion *resultArray = nullptr;
1853 switch (op)
1854 {
Olli Etuahof119a262016-08-19 15:54:22 +03001855 case EOpAny:
1856 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301857 resultArray = new TConstantUnion();
1858 resultArray->setBConst(false);
1859 for (size_t i = 0; i < objectSize; i++)
1860 {
1861 if (operandArray[i].getBConst())
1862 {
1863 resultArray->setBConst(true);
1864 break;
1865 }
1866 }
1867 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301868
Olli Etuahof119a262016-08-19 15:54:22 +03001869 case EOpAll:
1870 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301871 resultArray = new TConstantUnion();
1872 resultArray->setBConst(true);
1873 for (size_t i = 0; i < objectSize; i++)
1874 {
1875 if (!operandArray[i].getBConst())
1876 {
1877 resultArray->setBConst(false);
1878 break;
1879 }
1880 }
1881 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301882
Olli Etuahof119a262016-08-19 15:54:22 +03001883 case EOpLength:
1884 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301885 resultArray = new TConstantUnion();
1886 resultArray->setFConst(VectorLength(operandArray, objectSize));
1887 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301888
Olli Etuahof119a262016-08-19 15:54:22 +03001889 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301890 {
Olli Etuahof119a262016-08-19 15:54:22 +03001891 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301892 resultArray = new TConstantUnion[objectSize];
1893 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001894 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301895 SetUnionArrayFromMatrix(result, resultArray);
1896 break;
1897 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301898
Olli Etuahof119a262016-08-19 15:54:22 +03001899 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301900 {
Olli Etuahof119a262016-08-19 15:54:22 +03001901 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301902 unsigned int size = getType().getNominalSize();
1903 ASSERT(size >= 2 && size <= 4);
1904 resultArray = new TConstantUnion();
1905 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1906 break;
1907 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301908
Olli Etuahof119a262016-08-19 15:54:22 +03001909 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301910 {
Olli Etuahof119a262016-08-19 15:54:22 +03001911 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301912 unsigned int size = getType().getNominalSize();
1913 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001914 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301915 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1916 SetUnionArrayFromMatrix(result, resultArray);
1917 break;
1918 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301919
Olli Etuahof119a262016-08-19 15:54:22 +03001920 case EOpPackSnorm2x16:
1921 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301922 ASSERT(getType().getNominalSize() == 2);
1923 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001924 resultArray->setUConst(
1925 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301926 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301927
Olli Etuahof119a262016-08-19 15:54:22 +03001928 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301929 {
Olli Etuahof119a262016-08-19 15:54:22 +03001930 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301931 resultArray = new TConstantUnion[2];
1932 float f1, f2;
1933 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1934 resultArray[0].setFConst(f1);
1935 resultArray[1].setFConst(f2);
1936 break;
1937 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301938
Olli Etuahof119a262016-08-19 15:54:22 +03001939 case EOpPackUnorm2x16:
1940 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301941 ASSERT(getType().getNominalSize() == 2);
1942 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001943 resultArray->setUConst(
1944 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301946
Olli Etuahof119a262016-08-19 15:54:22 +03001947 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301948 {
Olli Etuahof119a262016-08-19 15:54:22 +03001949 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301950 resultArray = new TConstantUnion[2];
1951 float f1, f2;
1952 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1953 resultArray[0].setFConst(f1);
1954 resultArray[1].setFConst(f2);
1955 break;
1956 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301957
Olli Etuahof119a262016-08-19 15:54:22 +03001958 case EOpPackHalf2x16:
1959 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301960 ASSERT(getType().getNominalSize() == 2);
1961 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001962 resultArray->setUConst(
1963 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301964 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301965
Olli Etuahof119a262016-08-19 15:54:22 +03001966 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301967 {
Olli Etuahof119a262016-08-19 15:54:22 +03001968 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301969 resultArray = new TConstantUnion[2];
1970 float f1, f2;
1971 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1972 resultArray[0].setFConst(f1);
1973 resultArray[1].setFConst(f2);
1974 break;
1975 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301976
Olli Etuaho25aef452017-01-29 16:15:44 -08001977 case EOpPackUnorm4x8:
1978 {
1979 ASSERT(getType().getBasicType() == EbtFloat);
1980 resultArray = new TConstantUnion();
1981 resultArray->setUConst(
1982 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1983 operandArray[2].getFConst(), operandArray[3].getFConst()));
1984 break;
1985 }
1986 case EOpPackSnorm4x8:
1987 {
1988 ASSERT(getType().getBasicType() == EbtFloat);
1989 resultArray = new TConstantUnion();
1990 resultArray->setUConst(
1991 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1992 operandArray[2].getFConst(), operandArray[3].getFConst()));
1993 break;
1994 }
1995 case EOpUnpackUnorm4x8:
1996 {
1997 ASSERT(getType().getBasicType() == EbtUInt);
1998 resultArray = new TConstantUnion[4];
1999 float f[4];
2000 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2001 for (size_t i = 0; i < 4; ++i)
2002 {
2003 resultArray[i].setFConst(f[i]);
2004 }
2005 break;
2006 }
2007 case EOpUnpackSnorm4x8:
2008 {
2009 ASSERT(getType().getBasicType() == EbtUInt);
2010 resultArray = new TConstantUnion[4];
2011 float f[4];
2012 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2013 for (size_t i = 0; i < 4; ++i)
2014 {
2015 resultArray[i].setFConst(f[i]);
2016 }
2017 break;
2018 }
2019
Olli Etuahof119a262016-08-19 15:54:22 +03002020 default:
2021 UNREACHABLE();
2022 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302023 }
2024
2025 return resultArray;
2026}
2027
Olli Etuahof119a262016-08-19 15:54:22 +03002028TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2029 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302030{
Olli Etuahof119a262016-08-19 15:54:22 +03002031 // Do unary operations where each component of the result is computed based on the corresponding
2032 // component of the operand. Also folds normalize, though the divisor in that case takes all
2033 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302034
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002035 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002036 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002037
2038 size_t objectSize = getType().getObjectSize();
2039
Arun Patoleab2b9a22015-07-06 18:27:56 +05302040 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2041 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302042 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002043 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302044 {
Olli Etuahof119a262016-08-19 15:54:22 +03002045 case EOpNegative:
2046 switch (getType().getBasicType())
2047 {
2048 case EbtFloat:
2049 resultArray[i].setFConst(-operandArray[i].getFConst());
2050 break;
2051 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002052 if (operandArray[i] == std::numeric_limits<int>::min())
2053 {
2054 // The minimum representable integer doesn't have a positive
2055 // counterpart, rather the negation overflows and in ESSL is supposed to
2056 // wrap back to the minimum representable integer. Make sure that we
2057 // don't actually let the negation overflow, which has undefined
2058 // behavior in C++.
2059 resultArray[i].setIConst(std::numeric_limits<int>::min());
2060 }
2061 else
2062 {
2063 resultArray[i].setIConst(-operandArray[i].getIConst());
2064 }
Olli Etuahof119a262016-08-19 15:54:22 +03002065 break;
2066 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002067 if (operandArray[i] == 0x80000000u)
2068 {
2069 resultArray[i].setUConst(0x80000000u);
2070 }
2071 else
2072 {
2073 resultArray[i].setUConst(static_cast<unsigned int>(
2074 -static_cast<int>(operandArray[i].getUConst())));
2075 }
Olli Etuahof119a262016-08-19 15:54:22 +03002076 break;
2077 default:
2078 UNREACHABLE();
2079 return nullptr;
2080 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302081 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302082
Olli Etuahof119a262016-08-19 15:54:22 +03002083 case EOpPositive:
2084 switch (getType().getBasicType())
2085 {
2086 case EbtFloat:
2087 resultArray[i].setFConst(operandArray[i].getFConst());
2088 break;
2089 case EbtInt:
2090 resultArray[i].setIConst(operandArray[i].getIConst());
2091 break;
2092 case EbtUInt:
2093 resultArray[i].setUConst(static_cast<unsigned int>(
2094 static_cast<int>(operandArray[i].getUConst())));
2095 break;
2096 default:
2097 UNREACHABLE();
2098 return nullptr;
2099 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302100 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302101
Olli Etuahof119a262016-08-19 15:54:22 +03002102 case EOpLogicalNot:
2103 switch (getType().getBasicType())
2104 {
2105 case EbtBool:
2106 resultArray[i].setBConst(!operandArray[i].getBConst());
2107 break;
2108 default:
2109 UNREACHABLE();
2110 return nullptr;
2111 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302112 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302113
Olli Etuahof119a262016-08-19 15:54:22 +03002114 case EOpBitwiseNot:
2115 switch (getType().getBasicType())
2116 {
2117 case EbtInt:
2118 resultArray[i].setIConst(~operandArray[i].getIConst());
2119 break;
2120 case EbtUInt:
2121 resultArray[i].setUConst(~operandArray[i].getUConst());
2122 break;
2123 default:
2124 UNREACHABLE();
2125 return nullptr;
2126 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302127 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302128
Olli Etuahof119a262016-08-19 15:54:22 +03002129 case EOpRadians:
2130 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302131 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2132 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302133
Olli Etuahof119a262016-08-19 15:54:22 +03002134 case EOpDegrees:
2135 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2137 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302138
Olli Etuahof119a262016-08-19 15:54:22 +03002139 case EOpSin:
2140 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302141 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302142
Olli Etuahof119a262016-08-19 15:54:22 +03002143 case EOpCos:
2144 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2145 break;
2146
2147 case EOpTan:
2148 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2149 break;
2150
2151 case EOpAsin:
2152 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2153 // 0.
2154 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2155 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2156 diagnostics, &resultArray[i]);
2157 else
2158 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2159 break;
2160
2161 case EOpAcos:
2162 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2163 // 0.
2164 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2165 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2166 diagnostics, &resultArray[i]);
2167 else
2168 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2169 break;
2170
2171 case EOpAtan:
2172 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2173 break;
2174
2175 case EOpSinh:
2176 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2177 break;
2178
2179 case EOpCosh:
2180 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2181 break;
2182
2183 case EOpTanh:
2184 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2185 break;
2186
2187 case EOpAsinh:
2188 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2189 break;
2190
2191 case EOpAcosh:
2192 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2193 if (operandArray[i].getFConst() < 1.0f)
2194 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2195 diagnostics, &resultArray[i]);
2196 else
2197 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2198 break;
2199
2200 case EOpAtanh:
2201 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2202 // 0.
2203 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2204 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2205 diagnostics, &resultArray[i]);
2206 else
2207 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2208 break;
2209
2210 case EOpAbs:
2211 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302212 {
Olli Etuahof119a262016-08-19 15:54:22 +03002213 case EbtFloat:
2214 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2215 break;
2216 case EbtInt:
2217 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2218 break;
2219 default:
2220 UNREACHABLE();
2221 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302222 }
2223 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002224
2225 case EOpSign:
2226 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302227 {
Olli Etuahof119a262016-08-19 15:54:22 +03002228 case EbtFloat:
2229 {
2230 float fConst = operandArray[i].getFConst();
2231 float fResult = 0.0f;
2232 if (fConst > 0.0f)
2233 fResult = 1.0f;
2234 else if (fConst < 0.0f)
2235 fResult = -1.0f;
2236 resultArray[i].setFConst(fResult);
2237 break;
2238 }
2239 case EbtInt:
2240 {
2241 int iConst = operandArray[i].getIConst();
2242 int iResult = 0;
2243 if (iConst > 0)
2244 iResult = 1;
2245 else if (iConst < 0)
2246 iResult = -1;
2247 resultArray[i].setIConst(iResult);
2248 break;
2249 }
2250 default:
2251 UNREACHABLE();
2252 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302253 }
2254 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302255
Olli Etuahof119a262016-08-19 15:54:22 +03002256 case EOpFloor:
2257 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2258 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302259
Olli Etuahof119a262016-08-19 15:54:22 +03002260 case EOpTrunc:
2261 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2262 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302263
Olli Etuahof119a262016-08-19 15:54:22 +03002264 case EOpRound:
2265 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2266 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302267
Olli Etuahof119a262016-08-19 15:54:22 +03002268 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302269 {
Olli Etuahof119a262016-08-19 15:54:22 +03002270 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302271 float x = operandArray[i].getFConst();
2272 float result;
2273 float fractPart = modff(x, &result);
2274 if (fabsf(fractPart) == 0.5f)
2275 result = 2.0f * roundf(x / 2.0f);
2276 else
2277 result = roundf(x);
2278 resultArray[i].setFConst(result);
2279 break;
2280 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302281
Olli Etuahof119a262016-08-19 15:54:22 +03002282 case EOpCeil:
2283 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2284 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302285
Olli Etuahof119a262016-08-19 15:54:22 +03002286 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302287 {
Olli Etuahof119a262016-08-19 15:54:22 +03002288 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302289 float x = operandArray[i].getFConst();
2290 resultArray[i].setFConst(x - floorf(x));
2291 break;
2292 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302293
Olli Etuahof119a262016-08-19 15:54:22 +03002294 case EOpIsNan:
2295 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302296 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2297 break;
Arun Patole551279e2015-07-07 18:18:23 +05302298
Olli Etuahof119a262016-08-19 15:54:22 +03002299 case EOpIsInf:
2300 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302301 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2302 break;
Arun Patole551279e2015-07-07 18:18:23 +05302303
Olli Etuahof119a262016-08-19 15:54:22 +03002304 case EOpFloatBitsToInt:
2305 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302306 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2307 break;
Arun Patole551279e2015-07-07 18:18:23 +05302308
Olli Etuahof119a262016-08-19 15:54:22 +03002309 case EOpFloatBitsToUint:
2310 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302311 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2312 break;
Arun Patole551279e2015-07-07 18:18:23 +05302313
Olli Etuahof119a262016-08-19 15:54:22 +03002314 case EOpIntBitsToFloat:
2315 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302316 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2317 break;
Arun Patole551279e2015-07-07 18:18:23 +05302318
Olli Etuahof119a262016-08-19 15:54:22 +03002319 case EOpUintBitsToFloat:
2320 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302321 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2322 break;
Arun Patole551279e2015-07-07 18:18:23 +05302323
Olli Etuahof119a262016-08-19 15:54:22 +03002324 case EOpExp:
2325 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2326 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302327
Olli Etuahof119a262016-08-19 15:54:22 +03002328 case EOpLog:
2329 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2330 if (operandArray[i].getFConst() <= 0.0f)
2331 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2332 diagnostics, &resultArray[i]);
2333 else
2334 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2335 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302336
Olli Etuahof119a262016-08-19 15:54:22 +03002337 case EOpExp2:
2338 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2339 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302340
Olli Etuahof119a262016-08-19 15:54:22 +03002341 case EOpLog2:
2342 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2343 // And log2f is not available on some plarforms like old android, so just using
2344 // log(x)/log(2) here.
2345 if (operandArray[i].getFConst() <= 0.0f)
2346 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2347 diagnostics, &resultArray[i]);
2348 else
2349 {
2350 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2351 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2352 }
2353 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302354
Olli Etuahof119a262016-08-19 15:54:22 +03002355 case EOpSqrt:
2356 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2357 if (operandArray[i].getFConst() < 0.0f)
2358 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2359 diagnostics, &resultArray[i]);
2360 else
2361 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2362 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302363
Olli Etuahof119a262016-08-19 15:54:22 +03002364 case EOpInverseSqrt:
2365 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2366 // so getting the square root first using builtin function sqrt() and then taking
2367 // its inverse.
2368 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2369 // result to 0.
2370 if (operandArray[i].getFConst() <= 0.0f)
2371 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2372 diagnostics, &resultArray[i]);
2373 else
2374 {
2375 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2376 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2377 }
2378 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302379
Olli Etuahod68924e2017-01-02 17:34:40 +00002380 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002381 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302382 resultArray[i].setBConst(!operandArray[i].getBConst());
2383 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302384
Olli Etuahof119a262016-08-19 15:54:22 +03002385 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302386 {
Olli Etuahof119a262016-08-19 15:54:22 +03002387 ASSERT(getType().getBasicType() == EbtFloat);
2388 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302389 float length = VectorLength(operandArray, objectSize);
2390 if (length)
2391 resultArray[i].setFConst(x / length);
2392 else
Olli Etuahof119a262016-08-19 15:54:22 +03002393 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2394 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302395 break;
2396 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002397 case EOpBitfieldReverse:
2398 {
2399 uint32_t value;
2400 if (getType().getBasicType() == EbtInt)
2401 {
2402 value = static_cast<uint32_t>(operandArray[i].getIConst());
2403 }
2404 else
2405 {
2406 ASSERT(getType().getBasicType() == EbtUInt);
2407 value = operandArray[i].getUConst();
2408 }
2409 uint32_t result = gl::BitfieldReverse(value);
2410 if (getType().getBasicType() == EbtInt)
2411 {
2412 resultArray[i].setIConst(static_cast<int32_t>(result));
2413 }
2414 else
2415 {
2416 resultArray[i].setUConst(result);
2417 }
2418 break;
2419 }
2420 case EOpBitCount:
2421 {
2422 uint32_t value;
2423 if (getType().getBasicType() == EbtInt)
2424 {
2425 value = static_cast<uint32_t>(operandArray[i].getIConst());
2426 }
2427 else
2428 {
2429 ASSERT(getType().getBasicType() == EbtUInt);
2430 value = operandArray[i].getUConst();
2431 }
2432 int result = gl::BitCount(value);
2433 resultArray[i].setIConst(result);
2434 break;
2435 }
2436 case EOpFindLSB:
2437 {
2438 uint32_t value;
2439 if (getType().getBasicType() == EbtInt)
2440 {
2441 value = static_cast<uint32_t>(operandArray[i].getIConst());
2442 }
2443 else
2444 {
2445 ASSERT(getType().getBasicType() == EbtUInt);
2446 value = operandArray[i].getUConst();
2447 }
2448 resultArray[i].setIConst(gl::FindLSB(value));
2449 break;
2450 }
2451 case EOpFindMSB:
2452 {
2453 uint32_t value;
2454 if (getType().getBasicType() == EbtInt)
2455 {
2456 int intValue = operandArray[i].getIConst();
2457 value = static_cast<uint32_t>(intValue);
2458 if (intValue < 0)
2459 {
2460 // Look for zero instead of one in value. This also handles the intValue ==
2461 // -1 special case, where the return value needs to be -1.
2462 value = ~value;
2463 }
2464 }
2465 else
2466 {
2467 ASSERT(getType().getBasicType() == EbtUInt);
2468 value = operandArray[i].getUConst();
2469 }
2470 resultArray[i].setIConst(gl::FindMSB(value));
2471 break;
2472 }
Olli Etuahof119a262016-08-19 15:54:22 +03002473 case EOpDFdx:
2474 case EOpDFdy:
2475 case EOpFwidth:
2476 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302477 // Derivatives of constant arguments should be 0.
2478 resultArray[i].setFConst(0.0f);
2479 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302480
Olli Etuahof119a262016-08-19 15:54:22 +03002481 default:
2482 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302483 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302484 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002485
Arun Patoleab2b9a22015-07-06 18:27:56 +05302486 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002487}
2488
Olli Etuahof119a262016-08-19 15:54:22 +03002489void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2490 FloatTypeUnaryFunc builtinFunc,
2491 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302492{
2493 ASSERT(builtinFunc);
2494
Olli Etuahof119a262016-08-19 15:54:22 +03002495 ASSERT(getType().getBasicType() == EbtFloat);
2496 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302497}
2498
Jamie Madillb1a85f42014-08-19 15:23:24 -04002499// static
Olli Etuahof119a262016-08-19 15:54:22 +03002500TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002501{
2502 ASSERT(aggregate->getSequence()->size() > 0u);
2503 size_t resultSize = aggregate->getType().getObjectSize();
2504 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2505 TBasicType basicType = aggregate->getBasicType();
2506
2507 size_t resultIndex = 0u;
2508
2509 if (aggregate->getSequence()->size() == 1u)
2510 {
2511 TIntermNode *argument = aggregate->getSequence()->front();
2512 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2513 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2514 // Check the special case of constructing a matrix diagonal from a single scalar,
2515 // or a vector from a single scalar.
2516 if (argumentConstant->getType().getObjectSize() == 1u)
2517 {
2518 if (aggregate->isMatrix())
2519 {
2520 int resultCols = aggregate->getType().getCols();
2521 int resultRows = aggregate->getType().getRows();
2522 for (int col = 0; col < resultCols; ++col)
2523 {
2524 for (int row = 0; row < resultRows; ++row)
2525 {
2526 if (col == row)
2527 {
2528 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2529 }
2530 else
2531 {
2532 resultArray[resultIndex].setFConst(0.0f);
2533 }
2534 ++resultIndex;
2535 }
2536 }
2537 }
2538 else
2539 {
2540 while (resultIndex < resultSize)
2541 {
2542 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2543 ++resultIndex;
2544 }
2545 }
2546 ASSERT(resultIndex == resultSize);
2547 return resultArray;
2548 }
2549 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2550 {
2551 // The special case of constructing a matrix from a matrix.
2552 int argumentCols = argumentConstant->getType().getCols();
2553 int argumentRows = argumentConstant->getType().getRows();
2554 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002555 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002556 for (int col = 0; col < resultCols; ++col)
2557 {
2558 for (int row = 0; row < resultRows; ++row)
2559 {
2560 if (col < argumentCols && row < argumentRows)
2561 {
2562 resultArray[resultIndex].cast(basicType,
2563 argumentUnionArray[col * argumentRows + row]);
2564 }
2565 else if (col == row)
2566 {
2567 resultArray[resultIndex].setFConst(1.0f);
2568 }
2569 else
2570 {
2571 resultArray[resultIndex].setFConst(0.0f);
2572 }
2573 ++resultIndex;
2574 }
2575 }
2576 ASSERT(resultIndex == resultSize);
2577 return resultArray;
2578 }
2579 }
2580
2581 for (TIntermNode *&argument : *aggregate->getSequence())
2582 {
2583 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2584 size_t argumentSize = argumentConstant->getType().getObjectSize();
2585 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2586 for (size_t i = 0u; i < argumentSize; ++i)
2587 {
2588 if (resultIndex >= resultSize)
2589 break;
2590 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2591 ++resultIndex;
2592 }
2593 }
2594 ASSERT(resultIndex == resultSize);
2595 return resultArray;
2596}
2597
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002598bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2599{
2600 switch (op)
2601 {
2602 case EOpAtan:
2603 case EOpPow:
2604 case EOpMod:
2605 case EOpMin:
2606 case EOpMax:
2607 case EOpClamp:
2608 case EOpMix:
2609 case EOpStep:
2610 case EOpSmoothStep:
2611 case EOpLdexp:
2612 case EOpMulMatrixComponentWise:
2613 case EOpOuterProduct:
2614 case EOpEqualComponentWise:
2615 case EOpNotEqualComponentWise:
2616 case EOpLessThanComponentWise:
2617 case EOpLessThanEqualComponentWise:
2618 case EOpGreaterThanComponentWise:
2619 case EOpGreaterThanEqualComponentWise:
2620 case EOpDistance:
2621 case EOpDot:
2622 case EOpCross:
2623 case EOpFaceforward:
2624 case EOpReflect:
2625 case EOpRefract:
2626 case EOpBitfieldExtract:
2627 case EOpBitfieldInsert:
2628 return true;
2629 default:
2630 return false;
2631 }
2632}
2633
Olli Etuaho1d122782015-11-06 15:35:17 +02002634// static
Olli Etuahof119a262016-08-19 15:54:22 +03002635TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2636 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302637{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002638 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002639 TIntermSequence *arguments = aggregate->getSequence();
2640 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2641 std::vector<const TConstantUnion *> unionArrays(argsCount);
2642 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002643 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302644 TBasicType basicType = EbtVoid;
2645 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002646 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302647 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002648 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2649 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302650
2651 if (i == 0)
2652 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002653 basicType = argConstant->getType().getBasicType();
2654 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302655 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002656 unionArrays[i] = argConstant->getUnionArrayPointer();
2657 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002658 if (objectSizes[i] > maxObjectSize)
2659 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302660 }
2661
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002662 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302663 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002664 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302665 if (objectSizes[i] != maxObjectSize)
2666 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2667 }
Arun Patole274f0702015-05-05 13:33:30 +05302668
Olli Etuahob43846e2015-06-02 18:18:57 +03002669 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002670
2671 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302672 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002673 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302674 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002675 ASSERT(basicType == EbtFloat);
2676 resultArray = new TConstantUnion[maxObjectSize];
2677 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302678 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002679 float y = unionArrays[0][i].getFConst();
2680 float x = unionArrays[1][i].getFConst();
2681 // Results are undefined if x and y are both 0.
2682 if (x == 0.0f && y == 0.0f)
2683 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2684 else
2685 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302686 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002687 break;
2688 }
Arun Patolebf790422015-05-18 17:53:04 +05302689
Olli Etuaho51182ab2017-01-22 00:12:29 +00002690 case EOpPow:
2691 {
2692 ASSERT(basicType == EbtFloat);
2693 resultArray = new TConstantUnion[maxObjectSize];
2694 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302695 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002696 float x = unionArrays[0][i].getFConst();
2697 float y = unionArrays[1][i].getFConst();
2698 // Results are undefined if x < 0.
2699 // Results are undefined if x = 0 and y <= 0.
2700 if (x < 0.0f)
2701 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2702 else if (x == 0.0f && y <= 0.0f)
2703 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2704 else
2705 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302706 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002707 break;
2708 }
Arun Patolebf790422015-05-18 17:53:04 +05302709
Olli Etuaho51182ab2017-01-22 00:12:29 +00002710 case EOpMod:
2711 {
2712 ASSERT(basicType == EbtFloat);
2713 resultArray = new TConstantUnion[maxObjectSize];
2714 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302715 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002716 float x = unionArrays[0][i].getFConst();
2717 float y = unionArrays[1][i].getFConst();
2718 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302719 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002720 break;
2721 }
Arun Patolebf790422015-05-18 17:53:04 +05302722
Olli Etuaho51182ab2017-01-22 00:12:29 +00002723 case EOpMin:
2724 {
2725 resultArray = new TConstantUnion[maxObjectSize];
2726 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302727 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002728 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302729 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002730 case EbtFloat:
2731 resultArray[i].setFConst(
2732 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2733 break;
2734 case EbtInt:
2735 resultArray[i].setIConst(
2736 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2737 break;
2738 case EbtUInt:
2739 resultArray[i].setUConst(
2740 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2741 break;
2742 default:
2743 UNREACHABLE();
2744 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302745 }
2746 }
2747 break;
Arun Patole274f0702015-05-05 13:33:30 +05302748 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002749
2750 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302751 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002752 resultArray = new TConstantUnion[maxObjectSize];
2753 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302754 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002755 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302756 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002757 case EbtFloat:
2758 resultArray[i].setFConst(
2759 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2760 break;
2761 case EbtInt:
2762 resultArray[i].setIConst(
2763 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2764 break;
2765 case EbtUInt:
2766 resultArray[i].setUConst(
2767 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2768 break;
2769 default:
2770 UNREACHABLE();
2771 break;
Arun Patole274f0702015-05-05 13:33:30 +05302772 }
2773 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002774 break;
Arun Patole274f0702015-05-05 13:33:30 +05302775 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002776
2777 case EOpStep:
2778 {
2779 ASSERT(basicType == EbtFloat);
2780 resultArray = new TConstantUnion[maxObjectSize];
2781 for (size_t i = 0; i < maxObjectSize; i++)
2782 resultArray[i].setFConst(
2783 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2784 break;
2785 }
2786
2787 case EOpLessThanComponentWise:
2788 {
2789 resultArray = new TConstantUnion[maxObjectSize];
2790 for (size_t i = 0; i < maxObjectSize; i++)
2791 {
2792 switch (basicType)
2793 {
2794 case EbtFloat:
2795 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2796 unionArrays[1][i].getFConst());
2797 break;
2798 case EbtInt:
2799 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2800 unionArrays[1][i].getIConst());
2801 break;
2802 case EbtUInt:
2803 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2804 unionArrays[1][i].getUConst());
2805 break;
2806 default:
2807 UNREACHABLE();
2808 break;
2809 }
2810 }
2811 break;
2812 }
2813
2814 case EOpLessThanEqualComponentWise:
2815 {
2816 resultArray = new TConstantUnion[maxObjectSize];
2817 for (size_t i = 0; i < maxObjectSize; i++)
2818 {
2819 switch (basicType)
2820 {
2821 case EbtFloat:
2822 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2823 unionArrays[1][i].getFConst());
2824 break;
2825 case EbtInt:
2826 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2827 unionArrays[1][i].getIConst());
2828 break;
2829 case EbtUInt:
2830 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2831 unionArrays[1][i].getUConst());
2832 break;
2833 default:
2834 UNREACHABLE();
2835 break;
2836 }
2837 }
2838 break;
2839 }
2840
2841 case EOpGreaterThanComponentWise:
2842 {
2843 resultArray = new TConstantUnion[maxObjectSize];
2844 for (size_t i = 0; i < maxObjectSize; i++)
2845 {
2846 switch (basicType)
2847 {
2848 case EbtFloat:
2849 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2850 unionArrays[1][i].getFConst());
2851 break;
2852 case EbtInt:
2853 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2854 unionArrays[1][i].getIConst());
2855 break;
2856 case EbtUInt:
2857 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2858 unionArrays[1][i].getUConst());
2859 break;
2860 default:
2861 UNREACHABLE();
2862 break;
2863 }
2864 }
2865 break;
2866 }
2867 case EOpGreaterThanEqualComponentWise:
2868 {
2869 resultArray = new TConstantUnion[maxObjectSize];
2870 for (size_t i = 0; i < maxObjectSize; i++)
2871 {
2872 switch (basicType)
2873 {
2874 case EbtFloat:
2875 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2876 unionArrays[1][i].getFConst());
2877 break;
2878 case EbtInt:
2879 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2880 unionArrays[1][i].getIConst());
2881 break;
2882 case EbtUInt:
2883 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2884 unionArrays[1][i].getUConst());
2885 break;
2886 default:
2887 UNREACHABLE();
2888 break;
2889 }
2890 }
2891 }
2892 break;
2893
2894 case EOpEqualComponentWise:
2895 {
2896 resultArray = new TConstantUnion[maxObjectSize];
2897 for (size_t i = 0; i < maxObjectSize; i++)
2898 {
2899 switch (basicType)
2900 {
2901 case EbtFloat:
2902 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2903 unionArrays[1][i].getFConst());
2904 break;
2905 case EbtInt:
2906 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2907 unionArrays[1][i].getIConst());
2908 break;
2909 case EbtUInt:
2910 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2911 unionArrays[1][i].getUConst());
2912 break;
2913 case EbtBool:
2914 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2915 unionArrays[1][i].getBConst());
2916 break;
2917 default:
2918 UNREACHABLE();
2919 break;
2920 }
2921 }
2922 break;
2923 }
2924
2925 case EOpNotEqualComponentWise:
2926 {
2927 resultArray = new TConstantUnion[maxObjectSize];
2928 for (size_t i = 0; i < maxObjectSize; i++)
2929 {
2930 switch (basicType)
2931 {
2932 case EbtFloat:
2933 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2934 unionArrays[1][i].getFConst());
2935 break;
2936 case EbtInt:
2937 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2938 unionArrays[1][i].getIConst());
2939 break;
2940 case EbtUInt:
2941 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2942 unionArrays[1][i].getUConst());
2943 break;
2944 case EbtBool:
2945 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2946 unionArrays[1][i].getBConst());
2947 break;
2948 default:
2949 UNREACHABLE();
2950 break;
2951 }
2952 }
2953 break;
2954 }
2955
2956 case EOpDistance:
2957 {
2958 ASSERT(basicType == EbtFloat);
2959 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2960 resultArray = new TConstantUnion();
2961 for (size_t i = 0; i < maxObjectSize; i++)
2962 {
2963 float x = unionArrays[0][i].getFConst();
2964 float y = unionArrays[1][i].getFConst();
2965 distanceArray[i].setFConst(x - y);
2966 }
2967 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2968 break;
2969 }
2970
2971 case EOpDot:
2972 ASSERT(basicType == EbtFloat);
2973 resultArray = new TConstantUnion();
2974 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2975 break;
2976
2977 case EOpCross:
2978 {
2979 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2980 resultArray = new TConstantUnion[maxObjectSize];
2981 float x0 = unionArrays[0][0].getFConst();
2982 float x1 = unionArrays[0][1].getFConst();
2983 float x2 = unionArrays[0][2].getFConst();
2984 float y0 = unionArrays[1][0].getFConst();
2985 float y1 = unionArrays[1][1].getFConst();
2986 float y2 = unionArrays[1][2].getFConst();
2987 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2988 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2989 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2990 break;
2991 }
2992
2993 case EOpReflect:
2994 {
2995 ASSERT(basicType == EbtFloat);
2996 // genType reflect (genType I, genType N) :
2997 // For the incident vector I and surface orientation N, returns the reflection
2998 // direction:
2999 // I - 2 * dot(N, I) * N.
3000 resultArray = new TConstantUnion[maxObjectSize];
3001 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3002 for (size_t i = 0; i < maxObjectSize; i++)
3003 {
3004 float result = unionArrays[0][i].getFConst() -
3005 2.0f * dotProduct * unionArrays[1][i].getFConst();
3006 resultArray[i].setFConst(result);
3007 }
3008 break;
3009 }
3010
3011 case EOpMulMatrixComponentWise:
3012 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003013 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3014 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003015 // Perform component-wise matrix multiplication.
3016 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003017 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003018 angle::Matrix<float> result =
3019 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3020 SetUnionArrayFromMatrix(result, resultArray);
3021 break;
3022 }
3023
3024 case EOpOuterProduct:
3025 {
3026 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003027 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3028 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003029 resultArray = new TConstantUnion[numRows * numCols];
3030 angle::Matrix<float> result =
3031 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3032 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3033 SetUnionArrayFromMatrix(result, resultArray);
3034 break;
3035 }
3036
3037 case EOpClamp:
3038 {
3039 resultArray = new TConstantUnion[maxObjectSize];
3040 for (size_t i = 0; i < maxObjectSize; i++)
3041 {
3042 switch (basicType)
3043 {
3044 case EbtFloat:
3045 {
3046 float x = unionArrays[0][i].getFConst();
3047 float min = unionArrays[1][i].getFConst();
3048 float max = unionArrays[2][i].getFConst();
3049 // Results are undefined if min > max.
3050 if (min > max)
3051 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3052 &resultArray[i]);
3053 else
3054 resultArray[i].setFConst(gl::clamp(x, min, max));
3055 break;
3056 }
3057
3058 case EbtInt:
3059 {
3060 int x = unionArrays[0][i].getIConst();
3061 int min = unionArrays[1][i].getIConst();
3062 int max = unionArrays[2][i].getIConst();
3063 // Results are undefined if min > max.
3064 if (min > max)
3065 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3066 &resultArray[i]);
3067 else
3068 resultArray[i].setIConst(gl::clamp(x, min, max));
3069 break;
3070 }
3071 case EbtUInt:
3072 {
3073 unsigned int x = unionArrays[0][i].getUConst();
3074 unsigned int min = unionArrays[1][i].getUConst();
3075 unsigned int max = unionArrays[2][i].getUConst();
3076 // Results are undefined if min > max.
3077 if (min > max)
3078 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3079 &resultArray[i]);
3080 else
3081 resultArray[i].setUConst(gl::clamp(x, min, max));
3082 break;
3083 }
3084 default:
3085 UNREACHABLE();
3086 break;
3087 }
3088 }
3089 break;
3090 }
3091
3092 case EOpMix:
3093 {
3094 ASSERT(basicType == EbtFloat);
3095 resultArray = new TConstantUnion[maxObjectSize];
3096 for (size_t i = 0; i < maxObjectSize; i++)
3097 {
3098 float x = unionArrays[0][i].getFConst();
3099 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003100 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003101 if (type == EbtFloat)
3102 {
3103 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3104 float a = unionArrays[2][i].getFConst();
3105 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3106 }
3107 else // 3rd parameter is EbtBool
3108 {
3109 ASSERT(type == EbtBool);
3110 // Selects which vector each returned component comes from.
3111 // For a component of a that is false, the corresponding component of x is
3112 // returned.
3113 // For a component of a that is true, the corresponding component of y is
3114 // returned.
3115 bool a = unionArrays[2][i].getBConst();
3116 resultArray[i].setFConst(a ? y : x);
3117 }
3118 }
3119 break;
3120 }
3121
3122 case EOpSmoothStep:
3123 {
3124 ASSERT(basicType == EbtFloat);
3125 resultArray = new TConstantUnion[maxObjectSize];
3126 for (size_t i = 0; i < maxObjectSize; i++)
3127 {
3128 float edge0 = unionArrays[0][i].getFConst();
3129 float edge1 = unionArrays[1][i].getFConst();
3130 float x = unionArrays[2][i].getFConst();
3131 // Results are undefined if edge0 >= edge1.
3132 if (edge0 >= edge1)
3133 {
3134 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3135 }
3136 else
3137 {
3138 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3139 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3140 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3141 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3142 }
3143 }
3144 break;
3145 }
3146
Olli Etuaho74da73f2017-02-01 15:37:48 +00003147 case EOpLdexp:
3148 {
3149 resultArray = new TConstantUnion[maxObjectSize];
3150 for (size_t i = 0; i < maxObjectSize; i++)
3151 {
3152 float x = unionArrays[0][i].getFConst();
3153 int exp = unionArrays[1][i].getIConst();
3154 if (exp > 128)
3155 {
3156 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3157 }
3158 else
3159 {
3160 resultArray[i].setFConst(gl::Ldexp(x, exp));
3161 }
3162 }
3163 break;
3164 }
3165
Jamie Madille72595b2017-06-06 15:12:26 -04003166 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003167 {
3168 ASSERT(basicType == EbtFloat);
3169 // genType faceforward(genType N, genType I, genType Nref) :
3170 // If dot(Nref, I) < 0 return N, otherwise return -N.
3171 resultArray = new TConstantUnion[maxObjectSize];
3172 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3173 for (size_t i = 0; i < maxObjectSize; i++)
3174 {
3175 if (dotProduct < 0)
3176 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3177 else
3178 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3179 }
3180 break;
3181 }
3182
3183 case EOpRefract:
3184 {
3185 ASSERT(basicType == EbtFloat);
3186 // genType refract(genType I, genType N, float eta) :
3187 // For the incident vector I and surface normal N, and the ratio of indices of
3188 // refraction eta,
3189 // return the refraction vector. The result is computed by
3190 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3191 // if (k < 0.0)
3192 // return genType(0.0)
3193 // else
3194 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3195 resultArray = new TConstantUnion[maxObjectSize];
3196 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3197 for (size_t i = 0; i < maxObjectSize; i++)
3198 {
3199 float eta = unionArrays[2][i].getFConst();
3200 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3201 if (k < 0.0f)
3202 resultArray[i].setFConst(0.0f);
3203 else
3204 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3205 (eta * dotProduct + sqrtf(k)) *
3206 unionArrays[1][i].getFConst());
3207 }
3208 break;
3209 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003210 case EOpBitfieldExtract:
3211 {
3212 resultArray = new TConstantUnion[maxObjectSize];
3213 for (size_t i = 0; i < maxObjectSize; ++i)
3214 {
3215 int offset = unionArrays[1][0].getIConst();
3216 int bits = unionArrays[2][0].getIConst();
3217 if (bits == 0)
3218 {
3219 if (aggregate->getBasicType() == EbtInt)
3220 {
3221 resultArray[i].setIConst(0);
3222 }
3223 else
3224 {
3225 ASSERT(aggregate->getBasicType() == EbtUInt);
3226 resultArray[i].setUConst(0);
3227 }
3228 }
3229 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3230 {
3231 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3232 &resultArray[i]);
3233 }
3234 else
3235 {
3236 // bits can be 32 here, so we need to avoid bit shift overflow.
3237 uint32_t maskMsb = 1u << (bits - 1);
3238 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3239 if (aggregate->getBasicType() == EbtInt)
3240 {
3241 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3242 uint32_t resultUnsigned = (value & mask) >> offset;
3243 if ((resultUnsigned & maskMsb) != 0)
3244 {
3245 // The most significant bits (from bits+1 to the most significant bit)
3246 // should be set to 1.
3247 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3248 resultUnsigned |= higherBitsMask;
3249 }
3250 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3251 }
3252 else
3253 {
3254 ASSERT(aggregate->getBasicType() == EbtUInt);
3255 uint32_t value = unionArrays[0][i].getUConst();
3256 resultArray[i].setUConst((value & mask) >> offset);
3257 }
3258 }
3259 }
3260 break;
3261 }
3262 case EOpBitfieldInsert:
3263 {
3264 resultArray = new TConstantUnion[maxObjectSize];
3265 for (size_t i = 0; i < maxObjectSize; ++i)
3266 {
3267 int offset = unionArrays[2][0].getIConst();
3268 int bits = unionArrays[3][0].getIConst();
3269 if (bits == 0)
3270 {
3271 if (aggregate->getBasicType() == EbtInt)
3272 {
3273 int32_t base = unionArrays[0][i].getIConst();
3274 resultArray[i].setIConst(base);
3275 }
3276 else
3277 {
3278 ASSERT(aggregate->getBasicType() == EbtUInt);
3279 uint32_t base = unionArrays[0][i].getUConst();
3280 resultArray[i].setUConst(base);
3281 }
3282 }
3283 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3284 {
3285 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3286 &resultArray[i]);
3287 }
3288 else
3289 {
3290 // bits can be 32 here, so we need to avoid bit shift overflow.
3291 uint32_t maskMsb = 1u << (bits - 1);
3292 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3293 uint32_t baseMask = ~insertMask;
3294 if (aggregate->getBasicType() == EbtInt)
3295 {
3296 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3297 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3298 uint32_t resultUnsigned =
3299 (base & baseMask) | ((insert << offset) & insertMask);
3300 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3301 }
3302 else
3303 {
3304 ASSERT(aggregate->getBasicType() == EbtUInt);
3305 uint32_t base = unionArrays[0][i].getUConst();
3306 uint32_t insert = unionArrays[1][i].getUConst();
3307 resultArray[i].setUConst((base & baseMask) |
3308 ((insert << offset) & insertMask));
3309 }
3310 }
3311 }
3312 break;
3313 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003314
3315 default:
3316 UNREACHABLE();
3317 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303318 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003319 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303320}
3321
Jamie Madill45bcc782016-11-07 13:58:48 -05003322} // namespace sh