blob: 18127bfefb6650cde57ee91dfedbe531ea50ccee [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040021#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040023#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040024
Jamie Madill45bcc782016-11-07 13:58:48 -050025namespace sh
26{
27
Jamie Madillb1a85f42014-08-19 15:23:24 -040028namespace
29{
30
Jamie Madilld7b1ab52016-12-12 14:42:19 -050031const float kPi = 3.14159265358979323846f;
Arun Patole9dea48f2015-04-02 11:45:09 +053032const float kDegreesToRadiansMultiplier = kPi / 180.0f;
33const float kRadiansToDegreesMultiplier = 180.0f / kPi;
34
Jamie Madillb1a85f42014-08-19 15:23:24 -040035TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
36{
37 return left > right ? left : right;
38}
39
Arun Patole274f0702015-05-05 13:33:30 +053040TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
41{
42 TConstantUnion *constUnion = new TConstantUnion[size];
43 for (unsigned int i = 0; i < size; ++i)
Jamie Madilld7b1ab52016-12-12 14:42:19 -050044 constUnion[i] = constant;
Arun Patole274f0702015-05-05 13:33:30 +053045
46 return constUnion;
47}
48
Olli Etuahof119a262016-08-19 15:54:22 +030049void UndefinedConstantFoldingError(const TSourceLoc &loc,
50 TOperator op,
51 TBasicType basicType,
52 TDiagnostics *diagnostics,
53 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053054{
Olli Etuahof119a262016-08-19 15:54:22 +030055 diagnostics->warning(loc, "operation result is undefined for the values passed in",
Olli Etuaho4de340a2016-12-16 09:32:03 +000056 GetOperatorString(op));
Arun Patolebf790422015-05-18 17:53:04 +053057
58 switch (basicType)
59 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050060 case EbtFloat:
61 result->setFConst(0.0f);
62 break;
63 case EbtInt:
64 result->setIConst(0);
65 break;
66 case EbtUInt:
67 result->setUConst(0u);
68 break;
69 case EbtBool:
70 result->setBConst(false);
71 break;
72 default:
73 break;
Arun Patolebf790422015-05-18 17:53:04 +053074 }
75}
76
Olli Etuaho5c0e0232015-11-11 15:55:59 +020077float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053078{
79 float result = 0.0f;
80 for (size_t i = 0; i < paramArraySize; i++)
81 {
82 float f = paramArray[i].getFConst();
83 result += f * f;
84 }
85 return sqrtf(result);
86}
87
Olli Etuaho5c0e0232015-11-11 15:55:59 +020088float VectorDotProduct(const TConstantUnion *paramArray1,
89 const TConstantUnion *paramArray2,
90 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053091{
92 float result = 0.0f;
93 for (size_t i = 0; i < paramArraySize; i++)
94 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
95 return result;
96}
97
Olli Etuaho3272a6d2016-08-29 17:54:50 +030098TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
Olli Etuaho7c3848e2015-11-04 13:19:17 +020099 const TIntermTyped *originalNode,
100 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300101{
102 if (constArray == nullptr)
103 {
104 return nullptr;
105 }
106 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200107 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300108 folded->setLine(originalNode->getLine());
109 return folded;
110}
111
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200112angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
113 const unsigned int &rows,
114 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530115{
116 std::vector<float> elements;
117 for (size_t i = 0; i < rows * cols; i++)
118 elements.push_back(paramArray[i].getFConst());
119 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300120 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
121 // so that the created matrix will have the expected dimensions after the transpose.
122 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530123}
124
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200125angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530126{
127 std::vector<float> elements;
128 for (size_t i = 0; i < size * size; i++)
129 elements.push_back(paramArray[i].getFConst());
130 // Transpose is used since the Matrix constructor expects arguments in row-major order,
131 // whereas the paramArray is in column-major order.
132 return angle::Matrix<float>(elements, size).transpose();
133}
134
135void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
136{
137 // Transpose is used since the input Matrix is in row-major order,
138 // whereas the actual result should be in column-major order.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500139 angle::Matrix<float> result = m.transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530140 std::vector<float> resultElements = result.elements();
141 for (size_t i = 0; i < resultElements.size(); i++)
142 resultArray[i].setFConst(resultElements[i]);
143}
144
Jamie Madillb1a85f42014-08-19 15:23:24 -0400145} // namespace anonymous
146
Olli Etuahoae4dbf32017-12-08 20:49:00 +0100147TName::TName(const TString *name) : mName(name ? (*name) : ""), mIsInternal(false)
148{
149}
150
Olli Etuaho1bb85282017-12-14 13:39:53 +0200151TName::TName(const TSymbol *symbol)
152 : mName(*symbol->name()), mIsInternal(symbol->symbolType() == SymbolType::AngleInternal)
153{
154}
155
Jamie Madillb1a85f42014-08-19 15:23:24 -0400156////////////////////////////////////////////////////////////////
157//
158// Member functions of the nodes used for building the tree.
159//
160////////////////////////////////////////////////////////////////
161
Olli Etuahod2a67b92014-10-21 16:42:57 +0300162void TIntermTyped::setTypePreservePrecision(const TType &t)
163{
164 TPrecision precision = getPrecision();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500165 mType = t;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300166 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
167 mType.setPrecision(precision);
168}
169
Jamie Madillb1a85f42014-08-19 15:23:24 -0400170#define REPLACE_IF_IS(node, type, original, replacement) \
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500171 if (node == original) \
172 { \
173 node = static_cast<type *>(replacement); \
174 return true; \
Jamie Madillb1a85f42014-08-19 15:23:24 -0400175 }
176
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500177bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400178{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300179 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400180 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
181 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
182 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100183 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400184 return false;
185}
186
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500187bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400188{
189 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
190 return false;
191}
192
Olli Etuahob6fa0432016-09-28 16:28:05 +0100193bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
194{
195 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
196 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
197 return false;
198}
199
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500200bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400201{
202 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
203 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
204 return false;
205}
206
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500207bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400208{
Olli Etuahoa2234302016-08-31 12:05:39 +0300209 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400210 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
211 return false;
212}
213
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000214bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
215{
216 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
217 return false;
218}
219
Olli Etuaho336b1472016-10-05 16:37:55 +0100220bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
221{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000222 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
Olli Etuaho336b1472016-10-05 16:37:55 +0100223 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
224 return false;
225}
226
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500227bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400228{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100229 return replaceChildNodeInternal(original, replacement);
230}
231
232bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
233{
234 return replaceChildNodeInternal(original, replacement);
235}
236
Olli Etuaho16c745a2017-01-16 17:02:27 +0000237bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
238{
239 return replaceChildNodeInternal(original, replacement);
240}
241
Olli Etuaho13389b62016-10-16 11:48:18 +0100242bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
243{
244 return replaceChildNodeInternal(original, replacement);
245}
246
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100247bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
248{
249 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400250 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100251 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400252 }
253 return false;
254}
255
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100256bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
257 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300258{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100259 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300260 {
261 if (*it == original)
262 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100263 it = getSequence()->erase(it);
264 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300265 return true;
266 }
267 }
268 return false;
269}
270
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100271bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
272 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300273{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100274 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300275 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300276 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300277 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100278 auto it = getSequence()->begin() + position;
279 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300280 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300281}
282
Olli Etuaho195be942017-12-04 23:40:14 +0200283TIntermSymbol::TIntermSymbol(const TVariable *variable)
Olli Etuahob6af22b2017-12-15 14:05:44 +0200284 : TIntermTyped(variable->getType()), mVariable(variable), mSymbol(variable->name())
Olli Etuaho195be942017-12-04 23:40:14 +0200285{
286 if (variable->symbolType() == SymbolType::AngleInternal)
287 {
288 mSymbol.setInternal(true);
289 }
290}
291
Olli Etuahob6af22b2017-12-15 14:05:44 +0200292const TSymbolUniqueId &TIntermSymbol::uniqueId() const
293{
294 return mVariable->uniqueId();
295}
296
Olli Etuahofe486322017-03-21 09:30:54 +0000297TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
298 TIntermSequence *arguments)
299{
Olli Etuaho0c371002017-12-13 17:00:25 +0400300 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000301}
302
Olli Etuaho0c371002017-12-13 17:00:25 +0400303TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
304 TIntermSequence *arguments)
Olli Etuahofe486322017-03-21 09:30:54 +0000305{
Olli Etuaho0c371002017-12-13 17:00:25 +0400306 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000307}
308
309TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
310 TIntermSequence *arguments)
311{
312 TIntermAggregate *callNode =
Olli Etuaho0c371002017-12-13 17:00:25 +0400313 new TIntermAggregate(&func, func.getReturnType(), EOpCallBuiltInFunction, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000314 // Note that name needs to be set before texture function type is determined.
315 callNode->setBuiltInFunctionPrecision();
316 return callNode;
317}
318
319TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
Olli Etuahofe486322017-03-21 09:30:54 +0000320 TIntermSequence *arguments)
321{
Olli Etuaho0c371002017-12-13 17:00:25 +0400322 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000323}
324
325TIntermAggregate *TIntermAggregate::Create(const TType &type,
326 TOperator op,
327 TIntermSequence *arguments)
328{
Olli Etuahofe486322017-03-21 09:30:54 +0000329 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400330 ASSERT(op != EOpCallInternalRawFunction); // Should use CreateRawFunctionCall
Olli Etuahofe486322017-03-21 09:30:54 +0000331 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
Olli Etuaho0c371002017-12-13 17:00:25 +0400332 ASSERT(op != EOpConstruct); // Should use CreateConstructor
333 return new TIntermAggregate(nullptr, type, op, arguments);
Olli Etuahofe486322017-03-21 09:30:54 +0000334}
335
Olli Etuaho0c371002017-12-13 17:00:25 +0400336TIntermAggregate::TIntermAggregate(const TFunction *func,
337 const TType &type,
338 TOperator op,
339 TIntermSequence *arguments)
340 : TIntermOperator(op),
341 mUseEmulatedFunction(false),
342 mGotPrecisionFromChildren(false),
343 mFunction(func)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800344{
345 if (arguments != nullptr)
346 {
347 mArguments.swap(*arguments);
348 }
Olli Etuaho1bb85282017-12-14 13:39:53 +0200349 ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800350 setTypePrecisionAndQualifier(type);
351}
352
353void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
354{
355 setType(type);
356 mType.setQualifier(EvqTemporary);
357 if (!isFunctionCall())
358 {
359 if (isConstructor())
360 {
361 // Structs should not be precision qualified, the individual members may be.
362 // Built-in types on the other hand should be precision qualified.
Olli Etuaho8fab3202017-05-08 18:22:22 +0300363 if (getBasicType() != EbtStruct)
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800364 {
365 setPrecisionFromChildren();
366 }
367 }
368 else
369 {
370 setPrecisionForBuiltInOp();
371 }
372 if (areChildrenConstQualified())
373 {
374 mType.setQualifier(EvqConst);
375 }
376 }
377}
378
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200379bool TIntermAggregate::areChildrenConstQualified()
380{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800381 for (TIntermNode *&arg : mArguments)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200382 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800383 TIntermTyped *typedArg = arg->getAsTyped();
384 if (typedArg && typedArg->getQualifier() != EvqConst)
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200385 {
386 return false;
387 }
388 }
389 return true;
390}
391
Olli Etuahod2a67b92014-10-21 16:42:57 +0300392void TIntermAggregate::setPrecisionFromChildren()
393{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300394 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300395 if (getBasicType() == EbtBool)
396 {
397 mType.setPrecision(EbpUndefined);
398 return;
399 }
400
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500401 TPrecision precision = EbpUndefined;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800402 TIntermSequence::iterator childIter = mArguments.begin();
403 while (childIter != mArguments.end())
Olli Etuahod2a67b92014-10-21 16:42:57 +0300404 {
405 TIntermTyped *typed = (*childIter)->getAsTyped();
406 if (typed)
407 precision = GetHigherPrecision(typed->getPrecision(), precision);
408 ++childIter;
409 }
410 mType.setPrecision(precision);
411}
412
Olli Etuaho9250cb22017-01-21 10:51:27 +0000413void TIntermAggregate::setPrecisionForBuiltInOp()
414{
415 ASSERT(!isConstructor());
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800416 ASSERT(!isFunctionCall());
Olli Etuaho9250cb22017-01-21 10:51:27 +0000417 if (!setPrecisionForSpecialBuiltInOp())
418 {
419 setPrecisionFromChildren();
420 }
421}
422
423bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
424{
425 switch (mOp)
426 {
427 case EOpBitfieldExtract:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800428 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
429 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000430 return true;
431 case EOpBitfieldInsert:
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800432 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
433 mArguments[1]->getAsTyped()->getPrecision()));
434 mGotPrecisionFromChildren = true;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000435 return true;
436 case EOpUaddCarry:
437 case EOpUsubBorrow:
438 mType.setPrecision(EbpHigh);
439 return true;
440 default:
441 return false;
442 }
443}
444
Olli Etuahod2a67b92014-10-21 16:42:57 +0300445void TIntermAggregate::setBuiltInFunctionPrecision()
446{
447 // All built-ins returning bool should be handled as ops, not functions.
448 ASSERT(getBasicType() != EbtBool);
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800449 ASSERT(mOp == EOpCallBuiltInFunction);
Olli Etuahod2a67b92014-10-21 16:42:57 +0300450
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800451 TPrecision precision = EbpUndefined;
452 for (TIntermNode *arg : mArguments)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300453 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800454 TIntermTyped *typed = arg->getAsTyped();
Olli Etuahod2a67b92014-10-21 16:42:57 +0300455 // ESSL spec section 8: texture functions get their precision from the sampler.
456 if (typed && IsSampler(typed->getBasicType()))
457 {
458 precision = typed->getPrecision();
459 break;
460 }
Olli Etuahod2a67b92014-10-21 16:42:57 +0300461 }
462 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
463 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho1bb85282017-12-14 13:39:53 +0200464 if (mFunction->name()->find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300465 mType.setPrecision(EbpHigh);
466 else
467 mType.setPrecision(precision);
468}
469
Olli Etuahof2209f72017-04-01 12:45:55 +0300470TString TIntermAggregate::getSymbolTableMangledName() const
471{
472 ASSERT(!isConstructor());
473 switch (mOp)
474 {
475 case EOpCallInternalRawFunction:
476 case EOpCallBuiltInFunction:
477 case EOpCallFunctionInAST:
Olli Etuaho1bb85282017-12-14 13:39:53 +0200478 return TFunction::GetMangledNameFromCall(*mFunction->name(), mArguments);
Olli Etuahof2209f72017-04-01 12:45:55 +0300479 default:
480 TString opString = GetOperatorString(mOp);
481 return TFunction::GetMangledNameFromCall(opString, mArguments);
482 }
483}
484
Olli Etuaho0c371002017-12-13 17:00:25 +0400485const char *TIntermAggregate::functionName() const
486{
487 ASSERT(!isConstructor());
488 switch (mOp)
489 {
490 case EOpCallInternalRawFunction:
491 case EOpCallBuiltInFunction:
492 case EOpCallFunctionInAST:
493 return mFunction->name()->c_str();
494 default:
495 return GetOperatorString(mOp);
496 }
497}
498
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300499bool TIntermAggregate::hasSideEffects() const
500{
Olli Etuaho0c371002017-12-13 17:00:25 +0400501 if (isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects())
Olli Etuahoa22aa4e2017-05-24 18:17:23 +0300502 {
503 for (TIntermNode *arg : mArguments)
504 {
505 if (arg->getAsTyped()->hasSideEffects())
506 {
507 return true;
508 }
509 }
510 return false;
511 }
512 // Conservatively assume most aggregate operators have side-effects
513 return true;
514}
515
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100516void TIntermBlock::appendStatement(TIntermNode *statement)
517{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300518 // Declaration nodes with no children can appear if it was an empty declaration or if all the
519 // declarators just added constants to the symbol table instead of generating code. We still
520 // need to add the declaration to the AST in that case because it might be relevant to the
521 // validity of switch/case.
522 if (statement != nullptr)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100523 {
524 mStatements.push_back(statement);
525 }
526}
527
Olli Etuaho16c745a2017-01-16 17:02:27 +0000528void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
529{
530 ASSERT(parameter != nullptr);
531 mParameters.push_back(parameter);
532}
533
Olli Etuaho13389b62016-10-16 11:48:18 +0100534void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
535{
536 ASSERT(declarator != nullptr);
537 ASSERT(declarator->getAsSymbolNode() != nullptr ||
538 (declarator->getAsBinaryNode() != nullptr &&
539 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
540 ASSERT(mDeclarators.empty() ||
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300541 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
Olli Etuaho13389b62016-10-16 11:48:18 +0100542 mDeclarators.push_back(declarator);
543}
544
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300545bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
546{
547 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
548 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
549 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
550 return false;
551}
552
Olli Etuaho57961272016-09-14 13:57:46 +0300553bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400554{
555 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100556 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
557 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400558 return false;
559}
560
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500561bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200562{
563 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100564 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuaho923ecef2017-10-11 12:01:38 +0300565 ASSERT(mStatementList);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200566 return false;
567}
568
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500569bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200570{
571 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
572 return false;
573}
574
Olli Etuahod7a25242015-08-18 13:49:45 +0300575TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
576{
577 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
578 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
579 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
580 mLine = node.mLine;
581}
582
Olli Etuahod4f4c112016-04-15 15:11:24 +0300583bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
584{
585 TIntermAggregate *constructor = getAsAggregate();
586 if (!constructor || !constructor->isConstructor())
587 {
588 return false;
589 }
590 for (TIntermNode *&node : *constructor->getSequence())
591 {
592 if (!node->getAsConstantUnion())
593 return false;
594 }
595 return true;
596}
597
Olli Etuahod7a25242015-08-18 13:49:45 +0300598TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
599{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200600 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300601}
602
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200603TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
604 : TIntermTyped(function->getReturnType()), mFunction(function)
Olli Etuahobd674552016-10-06 13:28:42 +0100605{
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200606 ASSERT(mFunction->symbolType() != SymbolType::Empty);
Olli Etuahobd674552016-10-06 13:28:42 +0100607}
608
Olli Etuahod7a25242015-08-18 13:49:45 +0300609TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
610 : TIntermOperator(node),
Olli Etuahod7a25242015-08-18 13:49:45 +0300611 mUseEmulatedFunction(node.mUseEmulatedFunction),
Olli Etuahobd674552016-10-06 13:28:42 +0100612 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
Olli Etuaho0c371002017-12-13 17:00:25 +0400613 mFunction(node.mFunction)
Olli Etuahod7a25242015-08-18 13:49:45 +0300614{
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800615 for (TIntermNode *arg : node.mArguments)
Olli Etuahod7a25242015-08-18 13:49:45 +0300616 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800617 TIntermTyped *typedArg = arg->getAsTyped();
618 ASSERT(typedArg != nullptr);
619 TIntermTyped *argCopy = typedArg->deepCopy();
620 mArguments.push_back(argCopy);
Olli Etuahod7a25242015-08-18 13:49:45 +0300621 }
622}
623
Olli Etuahofe486322017-03-21 09:30:54 +0000624TIntermAggregate *TIntermAggregate::shallowCopy() const
625{
626 TIntermSequence *copySeq = new TIntermSequence();
627 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
Olli Etuaho0c371002017-12-13 17:00:25 +0400628 TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq);
Olli Etuahofe486322017-03-21 09:30:54 +0000629 copyNode->setLine(mLine);
630 return copyNode;
631}
632
Olli Etuahob6fa0432016-09-28 16:28:05 +0100633TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
634{
635 TIntermTyped *operandCopy = node.mOperand->deepCopy();
636 ASSERT(operandCopy != nullptr);
637 mOperand = operandCopy;
Olli Etuahoc9da71f2017-03-06 16:28:54 +0000638 mSwizzleOffsets = node.mSwizzleOffsets;
Olli Etuahob6fa0432016-09-28 16:28:05 +0100639}
640
Olli Etuahod7a25242015-08-18 13:49:45 +0300641TIntermBinary::TIntermBinary(const TIntermBinary &node)
642 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
643{
644 TIntermTyped *leftCopy = node.mLeft->deepCopy();
645 TIntermTyped *rightCopy = node.mRight->deepCopy();
646 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
647 mLeft = leftCopy;
648 mRight = rightCopy;
649}
650
651TIntermUnary::TIntermUnary(const TIntermUnary &node)
652 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
653{
654 TIntermTyped *operandCopy = node.mOperand->deepCopy();
655 ASSERT(operandCopy != nullptr);
656 mOperand = operandCopy;
657}
658
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300659TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300660{
Olli Etuahod7a25242015-08-18 13:49:45 +0300661 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300662 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
663 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300664 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300665 mCondition = conditionCopy;
666 mTrueExpression = trueCopy;
667 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300668}
669
Jamie Madillb1a85f42014-08-19 15:23:24 -0400670bool TIntermOperator::isAssignment() const
671{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300672 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400673}
674
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300675bool TIntermOperator::isMultiplication() const
676{
677 switch (mOp)
678 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500679 case EOpMul:
680 case EOpMatrixTimesMatrix:
681 case EOpMatrixTimesVector:
682 case EOpMatrixTimesScalar:
683 case EOpVectorTimesMatrix:
684 case EOpVectorTimesScalar:
685 return true;
686 default:
687 return false;
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300688 }
689}
690
Jamie Madillb1a85f42014-08-19 15:23:24 -0400691bool TIntermOperator::isConstructor() const
692{
Olli Etuaho8fab3202017-05-08 18:22:22 +0300693 return (mOp == EOpConstruct);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400694}
695
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800696bool TIntermOperator::isFunctionCall() const
697{
698 switch (mOp)
699 {
700 case EOpCallFunctionInAST:
701 case EOpCallBuiltInFunction:
702 case EOpCallInternalRawFunction:
703 return true;
704 default:
705 return false;
706 }
707}
708
Olli Etuaho1dded802016-08-18 18:13:13 +0300709TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
710{
711 if (left.isMatrix())
712 {
713 if (right.isMatrix())
714 {
715 return EOpMatrixTimesMatrix;
716 }
717 else
718 {
719 if (right.isVector())
720 {
721 return EOpMatrixTimesVector;
722 }
723 else
724 {
725 return EOpMatrixTimesScalar;
726 }
727 }
728 }
729 else
730 {
731 if (right.isMatrix())
732 {
733 if (left.isVector())
734 {
735 return EOpVectorTimesMatrix;
736 }
737 else
738 {
739 return EOpMatrixTimesScalar;
740 }
741 }
742 else
743 {
744 // Neither operand is a matrix.
745 if (left.isVector() == right.isVector())
746 {
747 // Leave as component product.
748 return EOpMul;
749 }
750 else
751 {
752 return EOpVectorTimesScalar;
753 }
754 }
755 }
756}
757
758TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
759{
760 if (left.isMatrix())
761 {
762 if (right.isMatrix())
763 {
764 return EOpMatrixTimesMatrixAssign;
765 }
766 else
767 {
768 // right should be scalar, but this may not be validated yet.
769 return EOpMatrixTimesScalarAssign;
770 }
771 }
772 else
773 {
774 if (right.isMatrix())
775 {
776 // Left should be a vector, but this may not be validated yet.
777 return EOpVectorTimesMatrixAssign;
778 }
779 else
780 {
781 // Neither operand is a matrix.
782 if (left.isVector() == right.isVector())
783 {
784 // Leave as component product.
785 return EOpMulAssign;
786 }
787 else
788 {
789 // left should be vector and right should be scalar, but this may not be validated
790 // yet.
791 return EOpVectorTimesScalarAssign;
792 }
793 }
794 }
795}
796
Jamie Madillb1a85f42014-08-19 15:23:24 -0400797//
798// Make sure the type of a unary operator is appropriate for its
799// combination of operation and operand type.
800//
Olli Etuahoa2234302016-08-31 12:05:39 +0300801void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400802{
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300803 if (mOp == EOpArrayLength)
804 {
805 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
806 setType(TType(EbtInt, EbpUndefined, EvqConst));
807 return;
808 }
809
Olli Etuahoa2234302016-08-31 12:05:39 +0300810 TQualifier resultQualifier = EvqTemporary;
811 if (mOperand->getQualifier() == EvqConst)
812 resultQualifier = EvqConst;
813
814 unsigned char operandPrimarySize =
815 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400816 switch (mOp)
817 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300818 case EOpFloatBitsToInt:
819 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
820 break;
821 case EOpFloatBitsToUint:
822 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
823 break;
824 case EOpIntBitsToFloat:
825 case EOpUintBitsToFloat:
826 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
827 break;
828 case EOpPackSnorm2x16:
829 case EOpPackUnorm2x16:
830 case EOpPackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800831 case EOpPackUnorm4x8:
832 case EOpPackSnorm4x8:
Olli Etuahoa2234302016-08-31 12:05:39 +0300833 setType(TType(EbtUInt, EbpHigh, resultQualifier));
834 break;
835 case EOpUnpackSnorm2x16:
836 case EOpUnpackUnorm2x16:
837 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
838 break;
839 case EOpUnpackHalf2x16:
840 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
841 break;
Olli Etuaho25aef452017-01-29 16:15:44 -0800842 case EOpUnpackUnorm4x8:
843 case EOpUnpackSnorm4x8:
844 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
845 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300846 case EOpAny:
847 case EOpAll:
848 setType(TType(EbtBool, EbpUndefined, resultQualifier));
849 break;
850 case EOpLength:
851 case EOpDeterminant:
852 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
853 break;
854 case EOpTranspose:
855 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
856 static_cast<unsigned char>(mOperand->getType().getRows()),
857 static_cast<unsigned char>(mOperand->getType().getCols())));
858 break;
859 case EOpIsInf:
860 case EOpIsNan:
861 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
862 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +0000863 case EOpBitfieldReverse:
864 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
865 break;
866 case EOpBitCount:
867 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
868 break;
869 case EOpFindLSB:
870 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
871 break;
872 case EOpFindMSB:
873 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
874 break;
Olli Etuahoa2234302016-08-31 12:05:39 +0300875 default:
876 setType(mOperand->getType());
877 mType.setQualifier(resultQualifier);
878 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400879 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300880}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400881
Olli Etuahob6fa0432016-09-28 16:28:05 +0100882TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
883 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
884 mOperand(operand),
885 mSwizzleOffsets(swizzleOffsets)
886{
887 ASSERT(mSwizzleOffsets.size() <= 4);
888 promote();
889}
890
Olli Etuahoa2234302016-08-31 12:05:39 +0300891TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
892 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
893{
894 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400895}
896
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300897TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
898 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
899{
900 promote();
901}
902
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000903TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
904 : TIntermNode(), mSymbol(symbol)
905{
906 ASSERT(symbol);
907 setLine(line);
908}
909
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300910TIntermTernary::TIntermTernary(TIntermTyped *cond,
911 TIntermTyped *trueExpression,
912 TIntermTyped *falseExpression)
913 : TIntermTyped(trueExpression->getType()),
914 mCondition(cond),
915 mTrueExpression(trueExpression),
916 mFalseExpression(falseExpression)
917{
918 getTypePointer()->setQualifier(
919 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
920}
921
Olli Etuaho81629262017-04-19 11:56:01 +0300922TIntermLoop::TIntermLoop(TLoopType type,
923 TIntermNode *init,
924 TIntermTyped *cond,
925 TIntermTyped *expr,
926 TIntermBlock *body)
927 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
928{
929 // Declaration nodes with no children can appear if all the declarators just added constants to
930 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
931 if (mInit && mInit->getAsDeclarationNode() &&
932 mInit->getAsDeclarationNode()->getSequence()->empty())
933 {
934 mInit = nullptr;
935 }
936}
937
Olli Etuaho923ecef2017-10-11 12:01:38 +0300938TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
939 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
940{
941 // Prune empty false blocks so that there won't be unnecessary operations done on it.
942 if (mFalseBlock && mFalseBlock->getSequence()->empty())
943 {
944 mFalseBlock = nullptr;
945 }
946}
947
948TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
949 : TIntermNode(), mInit(init), mStatementList(statementList)
950{
951 ASSERT(mStatementList);
952}
953
954void TIntermSwitch::setStatementList(TIntermBlock *statementList)
955{
956 ASSERT(statementList);
957 mStatementList = statementList;
958}
959
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300960// static
961TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
962 TIntermTyped *trueExpression,
963 TIntermTyped *falseExpression)
964{
965 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
966 falseExpression->getQualifier() == EvqConst)
967 {
968 return EvqConst;
969 }
970 return EvqTemporary;
971}
972
Olli Etuahoeb7f90f2017-07-07 17:25:23 +0300973TIntermTyped *TIntermTernary::fold()
974{
975 if (mCondition->getAsConstantUnion())
976 {
977 if (mCondition->getAsConstantUnion()->getBConst(0))
978 {
979 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
980 return mTrueExpression;
981 }
982 else
983 {
984 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
985 return mFalseExpression;
986 }
987 }
988 return this;
989}
990
Olli Etuahob6fa0432016-09-28 16:28:05 +0100991void TIntermSwizzle::promote()
992{
993 TQualifier resultQualifier = EvqTemporary;
994 if (mOperand->getQualifier() == EvqConst)
995 resultQualifier = EvqConst;
996
997 auto numFields = mSwizzleOffsets.size();
998 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
999 static_cast<unsigned char>(numFields)));
1000}
1001
1002bool TIntermSwizzle::hasDuplicateOffsets() const
1003{
1004 int offsetCount[4] = {0u, 0u, 0u, 0u};
1005 for (const auto offset : mSwizzleOffsets)
1006 {
1007 offsetCount[offset]++;
1008 if (offsetCount[offset] > 1)
1009 {
1010 return true;
1011 }
1012 }
1013 return false;
1014}
1015
Olli Etuaho09b04a22016-12-15 13:30:26 +00001016bool TIntermSwizzle::offsetsMatch(int offset) const
1017{
1018 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1019}
1020
Olli Etuahob6fa0432016-09-28 16:28:05 +01001021void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1022{
1023 for (const int offset : mSwizzleOffsets)
1024 {
1025 switch (offset)
1026 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001027 case 0:
1028 *out << "x";
1029 break;
1030 case 1:
1031 *out << "y";
1032 break;
1033 case 2:
1034 *out << "z";
1035 break;
1036 case 3:
1037 *out << "w";
1038 break;
1039 default:
1040 UNREACHABLE();
Olli Etuahob6fa0432016-09-28 16:28:05 +01001041 }
1042 }
1043}
1044
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001045TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1046 const TIntermTyped *left,
1047 const TIntermTyped *right)
1048{
1049 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1050 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1051 right->getQualifier() != EvqConst)
1052 {
1053 return EvqTemporary;
1054 }
1055 return EvqConst;
1056}
Olli Etuahob6fa0432016-09-28 16:28:05 +01001057
1058// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001059void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -04001060{
Olli Etuaho1dded802016-08-18 18:13:13 +03001061 ASSERT(!isMultiplication() ||
1062 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1063
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001064 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1065 // version and so is not being set here.
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001066 if (mOp == EOpComma)
1067 {
1068 setType(mRight->getType());
1069 return;
1070 }
1071
Jamie Madillb1a85f42014-08-19 15:23:24 -04001072 // Base assumption: just make the type the same as the left
1073 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001074 setType(mLeft->getType());
1075
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001076 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001077 // Binary operations results in temporary variables unless both
1078 // operands are const.
1079 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1080 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001081 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001082 getTypePointer()->setQualifier(EvqTemporary);
1083 }
1084
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001085 // Handle indexing ops.
1086 switch (mOp)
1087 {
1088 case EOpIndexDirect:
1089 case EOpIndexIndirect:
1090 if (mLeft->isArray())
1091 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001092 mType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001093 }
1094 else if (mLeft->isMatrix())
1095 {
1096 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1097 static_cast<unsigned char>(mLeft->getRows())));
1098 }
1099 else if (mLeft->isVector())
1100 {
1101 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1102 }
1103 else
1104 {
1105 UNREACHABLE();
1106 }
1107 return;
1108 case EOpIndexDirectStruct:
1109 {
1110 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1111 const int i = mRight->getAsConstantUnion()->getIConst(0);
1112 setType(*fields[i]->type());
1113 getTypePointer()->setQualifier(resultQualifier);
1114 return;
1115 }
1116 case EOpIndexDirectInterfaceBlock:
1117 {
1118 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1119 const int i = mRight->getAsConstantUnion()->getIConst(0);
1120 setType(*fields[i]->type());
1121 getTypePointer()->setQualifier(resultQualifier);
1122 return;
1123 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001124 default:
1125 break;
1126 }
1127
1128 ASSERT(mLeft->isArray() == mRight->isArray());
1129
1130 // The result gets promoted to the highest precision.
1131 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1132 getTypePointer()->setPrecision(higherPrecision);
1133
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001134 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001135
1136 //
1137 // All scalars or structs. Code after this test assumes this case is removed!
1138 //
1139 if (nominalSize == 1)
1140 {
1141 switch (mOp)
1142 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001143 //
1144 // Promote to conditional
1145 //
1146 case EOpEqual:
1147 case EOpNotEqual:
1148 case EOpLessThan:
1149 case EOpGreaterThan:
1150 case EOpLessThanEqual:
1151 case EOpGreaterThanEqual:
1152 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1153 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001154
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001155 //
1156 // And and Or operate on conditionals
1157 //
1158 case EOpLogicalAnd:
1159 case EOpLogicalXor:
1160 case EOpLogicalOr:
1161 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1162 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1163 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001164
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001165 default:
1166 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001167 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001168 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001169 }
1170
1171 // If we reach here, at least one of the operands is vector or matrix.
1172 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001173 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +03001174
Jamie Madillb1a85f42014-08-19 15:23:24 -04001175 switch (mOp)
1176 {
Olli Etuaho1dded802016-08-18 18:13:13 +03001177 case EOpMul:
1178 break;
1179 case EOpMatrixTimesScalar:
1180 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -04001181 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001182 setType(TType(basicType, higherPrecision, resultQualifier,
1183 static_cast<unsigned char>(mRight->getCols()),
1184 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001185 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001186 break;
1187 case EOpMatrixTimesVector:
1188 setType(TType(basicType, higherPrecision, resultQualifier,
1189 static_cast<unsigned char>(mLeft->getRows()), 1));
1190 break;
1191 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001192 setType(TType(basicType, higherPrecision, resultQualifier,
1193 static_cast<unsigned char>(mRight->getCols()),
1194 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +03001195 break;
1196 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001197 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +03001198 static_cast<unsigned char>(nominalSize), 1));
1199 break;
1200 case EOpVectorTimesMatrix:
1201 setType(TType(basicType, higherPrecision, resultQualifier,
1202 static_cast<unsigned char>(mRight->getCols()), 1));
1203 break;
1204 case EOpMulAssign:
1205 case EOpVectorTimesScalarAssign:
1206 case EOpVectorTimesMatrixAssign:
1207 case EOpMatrixTimesScalarAssign:
1208 case EOpMatrixTimesMatrixAssign:
1209 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1210 break;
1211 case EOpAssign:
1212 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +03001213 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1214 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1215 break;
1216 case EOpAdd:
1217 case EOpSub:
1218 case EOpDiv:
1219 case EOpIMod:
1220 case EOpBitShiftLeft:
1221 case EOpBitShiftRight:
1222 case EOpBitwiseAnd:
1223 case EOpBitwiseXor:
1224 case EOpBitwiseOr:
1225 case EOpAddAssign:
1226 case EOpSubAssign:
1227 case EOpDivAssign:
1228 case EOpIModAssign:
1229 case EOpBitShiftLeftAssign:
1230 case EOpBitShiftRightAssign:
1231 case EOpBitwiseAndAssign:
1232 case EOpBitwiseXorAssign:
1233 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001234 {
1235 const int secondarySize =
1236 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1237 setType(TType(basicType, higherPrecision, resultQualifier,
1238 static_cast<unsigned char>(nominalSize),
1239 static_cast<unsigned char>(secondarySize)));
1240 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +03001241 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001242 }
Olli Etuaho1dded802016-08-18 18:13:13 +03001243 case EOpEqual:
1244 case EOpNotEqual:
1245 case EOpLessThan:
1246 case EOpGreaterThan:
1247 case EOpLessThanEqual:
1248 case EOpGreaterThanEqual:
1249 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1250 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001251 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001252 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001253
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001254 case EOpIndexDirect:
1255 case EOpIndexIndirect:
1256 case EOpIndexDirectInterfaceBlock:
1257 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001258 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001259 UNREACHABLE();
1260 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001261 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001262 UNREACHABLE();
1263 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001264 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001265}
1266
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001267const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001268{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001269 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001270 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001271 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001272 TType arrayElementType = getType();
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001273 arrayElementType.toArrayElementType();
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001274 size_t arrayElementSize = arrayElementType.getObjectSize();
1275 return &mUnionArrayPointer[arrayElementSize * index];
1276 }
1277 else if (isMatrix())
1278 {
1279 ASSERT(index < getType().getCols());
1280 int size = getType().getRows();
1281 return &mUnionArrayPointer[size * index];
1282 }
1283 else if (isVector())
1284 {
1285 ASSERT(index < getType().getNominalSize());
1286 return &mUnionArrayPointer[index];
1287 }
1288 else
1289 {
1290 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001291 return nullptr;
1292 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001293}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001294
Olli Etuahob6fa0432016-09-28 16:28:05 +01001295TIntermTyped *TIntermSwizzle::fold()
1296{
1297 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1298 if (operandConstant == nullptr)
1299 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001300 return this;
Olli Etuahob6fa0432016-09-28 16:28:05 +01001301 }
1302
1303 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1304 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1305 {
1306 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1307 }
1308 return CreateFoldedNode(constArray, this, mType.getQualifier());
1309}
1310
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001311TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1312{
1313 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1314 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1315 switch (mOp)
1316 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001317 case EOpComma:
1318 {
1319 if (mLeft->hasSideEffects())
1320 {
1321 return this;
1322 }
1323 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1324 return mRight;
1325 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001326 case EOpIndexDirect:
1327 {
1328 if (leftConstant == nullptr || rightConstant == nullptr)
1329 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001330 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001331 }
1332 int index = rightConstant->getIConst(0);
1333
1334 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001335 if (!constArray)
1336 {
1337 return this;
1338 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001339 return CreateFoldedNode(constArray, this, mType.getQualifier());
1340 }
1341 case EOpIndexDirectStruct:
1342 {
1343 if (leftConstant == nullptr || rightConstant == nullptr)
1344 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001345 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001346 }
1347 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1348 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1349
1350 size_t previousFieldsSize = 0;
1351 for (size_t i = 0; i < index; ++i)
1352 {
1353 previousFieldsSize += fields[i]->type()->getObjectSize();
1354 }
1355
1356 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1357 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1358 }
1359 case EOpIndexIndirect:
1360 case EOpIndexDirectInterfaceBlock:
1361 // Can never be constant folded.
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001362 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001363 default:
1364 {
1365 if (leftConstant == nullptr || rightConstant == nullptr)
1366 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001367 return this;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001368 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001369 TConstantUnion *constArray =
1370 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001371 if (!constArray)
1372 {
1373 return this;
1374 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001375
1376 // Nodes may be constant folded without being qualified as constant.
1377 return CreateFoldedNode(constArray, this, mType.getQualifier());
1378 }
1379 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001380}
1381
Olli Etuahof119a262016-08-19 15:54:22 +03001382TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001383{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301384 TConstantUnion *constArray = nullptr;
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001385
1386 if (mOp == EOpArrayLength)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301387 {
Olli Etuahoebee5b32017-11-23 12:56:32 +02001388 // The size of runtime-sized arrays may only be determined at runtime.
1389 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
Olli Etuahobb2bbfb2017-08-24 15:43:33 +03001390 {
1391 return this;
1392 }
1393 constArray = new TConstantUnion[1];
1394 constArray->setIConst(mOperand->getOutermostArraySize());
1395 }
1396 else
1397 {
1398 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1399 if (operandConstant == nullptr)
1400 {
1401 return this;
1402 }
1403
1404 switch (mOp)
1405 {
1406 case EOpAny:
1407 case EOpAll:
1408 case EOpLength:
1409 case EOpTranspose:
1410 case EOpDeterminant:
1411 case EOpInverse:
1412 case EOpPackSnorm2x16:
1413 case EOpUnpackSnorm2x16:
1414 case EOpPackUnorm2x16:
1415 case EOpUnpackUnorm2x16:
1416 case EOpPackHalf2x16:
1417 case EOpUnpackHalf2x16:
1418 case EOpPackUnorm4x8:
1419 case EOpPackSnorm4x8:
1420 case EOpUnpackUnorm4x8:
1421 case EOpUnpackSnorm4x8:
1422 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1423 break;
1424 default:
1425 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1426 break;
1427 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301428 }
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001429 if (constArray == nullptr)
1430 {
1431 return this;
1432 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001433
1434 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001435 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001436}
1437
Olli Etuahof119a262016-08-19 15:54:22 +03001438TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001439{
1440 // Make sure that all params are constant before actual constant folding.
1441 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001442 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001443 if (param->getAsConstantUnion() == nullptr)
1444 {
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03001445 return this;
Olli Etuahob43846e2015-06-02 18:18:57 +03001446 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001447 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001448 TConstantUnion *constArray = nullptr;
1449 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001450 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001451 else
Olli Etuahof119a262016-08-19 15:54:22 +03001452 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001453
1454 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08001455 return CreateFoldedNode(constArray, this, getQualifier());
Olli Etuaho95310b02015-06-02 17:43:38 +03001456}
1457
Jamie Madillb1a85f42014-08-19 15:23:24 -04001458//
1459// The fold functions see if an operation on a constant can be done in place,
1460// without generating run-time code.
1461//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001462// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001463//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001464TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1465 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001466 TDiagnostics *diagnostics,
1467 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001468{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001469 const TConstantUnion *leftArray = getUnionArrayPointer();
1470 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001471
Olli Etuahof119a262016-08-19 15:54:22 +03001472 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001473
1474 size_t objectSize = getType().getObjectSize();
1475
1476 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1477 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1478 {
1479 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1480 }
1481 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1482 {
1483 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001484 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001485 objectSize = rightNode->getType().getObjectSize();
1486 }
1487
1488 TConstantUnion *resultArray = nullptr;
1489
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001490 switch (op)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001491 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001492 case EOpAdd:
1493 resultArray = new TConstantUnion[objectSize];
1494 for (size_t i = 0; i < objectSize; i++)
1495 resultArray[i] =
1496 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1497 break;
1498 case EOpSub:
1499 resultArray = new TConstantUnion[objectSize];
1500 for (size_t i = 0; i < objectSize; i++)
1501 resultArray[i] =
1502 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1503 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001504
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001505 case EOpMul:
1506 case EOpVectorTimesScalar:
1507 case EOpMatrixTimesScalar:
1508 resultArray = new TConstantUnion[objectSize];
1509 for (size_t i = 0; i < objectSize; i++)
1510 resultArray[i] =
1511 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1512 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001513
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001514 case EOpMatrixTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001515 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001516 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001517 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001518
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001519 const int leftCols = getCols();
1520 const int leftRows = getRows();
1521 const int rightCols = rightNode->getType().getCols();
1522 const int rightRows = rightNode->getType().getRows();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001523 const int resultCols = rightCols;
1524 const int resultRows = leftRows;
1525
1526 resultArray = new TConstantUnion[resultCols * resultRows];
1527 for (int row = 0; row < resultRows; row++)
1528 {
1529 for (int column = 0; column < resultCols; column++)
1530 {
1531 resultArray[resultRows * column + row].setFConst(0.0f);
1532 for (int i = 0; i < leftCols; i++)
1533 {
1534 resultArray[resultRows * column + row].setFConst(
1535 resultArray[resultRows * column + row].getFConst() +
1536 leftArray[i * leftRows + row].getFConst() *
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001537 rightArray[column * rightRows + i].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001538 }
1539 }
1540 }
1541 }
1542 break;
1543
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001544 case EOpDiv:
1545 case EOpIMod:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001546 {
1547 resultArray = new TConstantUnion[objectSize];
1548 for (size_t i = 0; i < objectSize; i++)
1549 {
1550 switch (getType().getBasicType())
1551 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001552 case EbtFloat:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001553 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001554 ASSERT(op == EOpDiv);
1555 float dividend = leftArray[i].getFConst();
1556 float divisor = rightArray[i].getFConst();
1557 if (divisor == 0.0f)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001558 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001559 if (dividend == 0.0f)
Olli Etuahod4453572016-09-27 13:21:46 +01001560 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001561 diagnostics->warning(
1562 getLine(),
1563 "Zero divided by zero during constant folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001564 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001565 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
Olli Etuahod4453572016-09-27 13:21:46 +01001566 }
1567 else
1568 {
Olli Etuaho4de340a2016-12-16 09:32:03 +00001569 diagnostics->warning(getLine(),
1570 "Divide by zero during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001571 bool negativeResult =
1572 std::signbit(dividend) != std::signbit(divisor);
1573 resultArray[i].setFConst(
1574 negativeResult ? -std::numeric_limits<float>::infinity()
1575 : std::numeric_limits<float>::infinity());
Olli Etuahod4453572016-09-27 13:21:46 +01001576 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001577 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001578 else if (gl::isInf(dividend) && gl::isInf(divisor))
1579 {
1580 diagnostics->warning(getLine(),
1581 "Infinity divided by infinity during constant "
1582 "folding generated NaN",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001583 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001584 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1585 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001586 else
1587 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001588 float result = dividend / divisor;
1589 if (!gl::isInf(dividend) && gl::isInf(result))
Olli Etuahod4453572016-09-27 13:21:46 +01001590 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001591 diagnostics->warning(
1592 getLine(), "Constant folded division overflowed to infinity",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001593 "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001594 }
1595 resultArray[i].setFConst(result);
1596 }
1597 break;
1598 }
1599 case EbtInt:
1600 if (rightArray[i] == 0)
1601 {
1602 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001603 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001604 resultArray[i].setIConst(INT_MAX);
1605 }
1606 else
1607 {
1608 int lhs = leftArray[i].getIConst();
1609 int divisor = rightArray[i].getIConst();
1610 if (op == EOpDiv)
1611 {
1612 // Check for the special case where the minimum representable number
1613 // is
1614 // divided by -1. If left alone this leads to integer overflow in
1615 // C++.
1616 // ESSL 3.00.6 section 4.1.3 Integers:
1617 // "However, for the case where the minimum representable value is
1618 // divided by -1, it is allowed to return either the minimum
1619 // representable value or the maximum representable value."
1620 if (lhs == -0x7fffffff - 1 && divisor == -1)
1621 {
1622 resultArray[i].setIConst(0x7fffffff);
1623 }
1624 else
1625 {
1626 resultArray[i].setIConst(lhs / divisor);
1627 }
Olli Etuahod4453572016-09-27 13:21:46 +01001628 }
1629 else
1630 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001631 ASSERT(op == EOpIMod);
1632 if (lhs < 0 || divisor < 0)
1633 {
1634 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1635 // when
1636 // either one of the operands is negative.
1637 diagnostics->warning(getLine(),
1638 "Negative modulus operator operand "
1639 "encountered during constant folding",
Olli Etuaho4de340a2016-12-16 09:32:03 +00001640 "%");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001641 resultArray[i].setIConst(0);
1642 }
1643 else
1644 {
1645 resultArray[i].setIConst(lhs % divisor);
1646 }
Olli Etuahod4453572016-09-27 13:21:46 +01001647 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001648 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001649 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001650
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001651 case EbtUInt:
1652 if (rightArray[i] == 0)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001653 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001654 diagnostics->warning(
Olli Etuaho4de340a2016-12-16 09:32:03 +00001655 getLine(), "Divide by zero error during constant folding", "/");
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001656 resultArray[i].setUConst(UINT_MAX);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001657 }
1658 else
1659 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001660 if (op == EOpDiv)
1661 {
1662 resultArray[i].setUConst(leftArray[i].getUConst() /
1663 rightArray[i].getUConst());
1664 }
1665 else
1666 {
1667 ASSERT(op == EOpIMod);
1668 resultArray[i].setUConst(leftArray[i].getUConst() %
1669 rightArray[i].getUConst());
1670 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001671 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001672 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001673
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001674 default:
1675 UNREACHABLE();
1676 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001677 }
1678 }
1679 }
1680 break;
1681
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001682 case EOpMatrixTimesVector:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001683 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001684 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001685 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001686
1687 const int matrixCols = getCols();
1688 const int matrixRows = getRows();
1689
1690 resultArray = new TConstantUnion[matrixRows];
1691
1692 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1693 {
1694 resultArray[matrixRow].setFConst(0.0f);
1695 for (int col = 0; col < matrixCols; col++)
1696 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001697 resultArray[matrixRow].setFConst(
1698 resultArray[matrixRow].getFConst() +
1699 leftArray[col * matrixRows + matrixRow].getFConst() *
1700 rightArray[col].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001701 }
1702 }
1703 }
1704 break;
1705
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001706 case EOpVectorTimesMatrix:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001707 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001708 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001709 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001710
1711 const int matrixCols = rightNode->getType().getCols();
1712 const int matrixRows = rightNode->getType().getRows();
1713
1714 resultArray = new TConstantUnion[matrixCols];
1715
1716 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1717 {
1718 resultArray[matrixCol].setFConst(0.0f);
1719 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1720 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001721 resultArray[matrixCol].setFConst(
1722 resultArray[matrixCol].getFConst() +
1723 leftArray[matrixRow].getFConst() *
1724 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001725 }
1726 }
1727 }
1728 break;
1729
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001730 case EOpLogicalAnd:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001731 {
1732 resultArray = new TConstantUnion[objectSize];
1733 for (size_t i = 0; i < objectSize; i++)
1734 {
1735 resultArray[i] = leftArray[i] && rightArray[i];
1736 }
1737 }
1738 break;
1739
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001740 case EOpLogicalOr:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001741 {
1742 resultArray = new TConstantUnion[objectSize];
1743 for (size_t i = 0; i < objectSize; i++)
1744 {
1745 resultArray[i] = leftArray[i] || rightArray[i];
1746 }
1747 }
1748 break;
1749
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001750 case EOpLogicalXor:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001751 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001752 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001753 resultArray = new TConstantUnion[objectSize];
1754 for (size_t i = 0; i < objectSize; i++)
1755 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001756 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001757 }
1758 }
1759 break;
1760
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001761 case EOpBitwiseAnd:
1762 resultArray = new TConstantUnion[objectSize];
1763 for (size_t i = 0; i < objectSize; i++)
1764 resultArray[i] = leftArray[i] & rightArray[i];
1765 break;
1766 case EOpBitwiseXor:
1767 resultArray = new TConstantUnion[objectSize];
1768 for (size_t i = 0; i < objectSize; i++)
1769 resultArray[i] = leftArray[i] ^ rightArray[i];
1770 break;
1771 case EOpBitwiseOr:
1772 resultArray = new TConstantUnion[objectSize];
1773 for (size_t i = 0; i < objectSize; i++)
1774 resultArray[i] = leftArray[i] | rightArray[i];
1775 break;
1776 case EOpBitShiftLeft:
1777 resultArray = new TConstantUnion[objectSize];
1778 for (size_t i = 0; i < objectSize; i++)
1779 resultArray[i] =
1780 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1781 break;
1782 case EOpBitShiftRight:
1783 resultArray = new TConstantUnion[objectSize];
1784 for (size_t i = 0; i < objectSize; i++)
1785 resultArray[i] =
1786 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1787 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001788
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001789 case EOpLessThan:
1790 ASSERT(objectSize == 1);
1791 resultArray = new TConstantUnion[1];
1792 resultArray->setBConst(*leftArray < *rightArray);
1793 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001794
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001795 case EOpGreaterThan:
1796 ASSERT(objectSize == 1);
1797 resultArray = new TConstantUnion[1];
1798 resultArray->setBConst(*leftArray > *rightArray);
1799 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001800
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001801 case EOpLessThanEqual:
1802 ASSERT(objectSize == 1);
1803 resultArray = new TConstantUnion[1];
1804 resultArray->setBConst(!(*leftArray > *rightArray));
1805 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001806
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001807 case EOpGreaterThanEqual:
1808 ASSERT(objectSize == 1);
1809 resultArray = new TConstantUnion[1];
1810 resultArray->setBConst(!(*leftArray < *rightArray));
1811 break;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001812
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001813 case EOpEqual:
1814 case EOpNotEqual:
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001815 {
1816 resultArray = new TConstantUnion[1];
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001817 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001818 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001819 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001820 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001821 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001822 equal = false;
1823 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001824 }
1825 }
1826 if (op == EOpEqual)
1827 {
1828 resultArray->setBConst(equal);
1829 }
1830 else
1831 {
1832 resultArray->setBConst(!equal);
1833 }
1834 }
1835 break;
1836
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001837 default:
1838 UNREACHABLE();
1839 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001840 }
1841 return resultArray;
1842}
1843
Olli Etuahof119a262016-08-19 15:54:22 +03001844// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1845// code. Returns the constant value to keep using. Nullptr should not be returned.
1846TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001847{
Olli Etuahof119a262016-08-19 15:54:22 +03001848 // Do operations where the return type may have a different number of components compared to the
1849 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001850
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001851 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001852 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301853
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001854 size_t objectSize = getType().getObjectSize();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301855 TConstantUnion *resultArray = nullptr;
1856 switch (op)
1857 {
Olli Etuahof119a262016-08-19 15:54:22 +03001858 case EOpAny:
1859 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301860 resultArray = new TConstantUnion();
1861 resultArray->setBConst(false);
1862 for (size_t i = 0; i < objectSize; i++)
1863 {
1864 if (operandArray[i].getBConst())
1865 {
1866 resultArray->setBConst(true);
1867 break;
1868 }
1869 }
1870 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301871
Olli Etuahof119a262016-08-19 15:54:22 +03001872 case EOpAll:
1873 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301874 resultArray = new TConstantUnion();
1875 resultArray->setBConst(true);
1876 for (size_t i = 0; i < objectSize; i++)
1877 {
1878 if (!operandArray[i].getBConst())
1879 {
1880 resultArray->setBConst(false);
1881 break;
1882 }
1883 }
1884 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301885
Olli Etuahof119a262016-08-19 15:54:22 +03001886 case EOpLength:
1887 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301888 resultArray = new TConstantUnion();
1889 resultArray->setFConst(VectorLength(operandArray, objectSize));
1890 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301891
Olli Etuahof119a262016-08-19 15:54:22 +03001892 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301893 {
Olli Etuahof119a262016-08-19 15:54:22 +03001894 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301895 resultArray = new TConstantUnion[objectSize];
1896 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001897 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301898 SetUnionArrayFromMatrix(result, resultArray);
1899 break;
1900 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301901
Olli Etuahof119a262016-08-19 15:54:22 +03001902 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301903 {
Olli Etuahof119a262016-08-19 15:54:22 +03001904 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301905 unsigned int size = getType().getNominalSize();
1906 ASSERT(size >= 2 && size <= 4);
1907 resultArray = new TConstantUnion();
1908 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1909 break;
1910 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301911
Olli Etuahof119a262016-08-19 15:54:22 +03001912 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301913 {
Olli Etuahof119a262016-08-19 15:54:22 +03001914 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301915 unsigned int size = getType().getNominalSize();
1916 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001917 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301918 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1919 SetUnionArrayFromMatrix(result, resultArray);
1920 break;
1921 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301922
Olli Etuahof119a262016-08-19 15:54:22 +03001923 case EOpPackSnorm2x16:
1924 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301925 ASSERT(getType().getNominalSize() == 2);
1926 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001927 resultArray->setUConst(
1928 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301929 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301930
Olli Etuahof119a262016-08-19 15:54:22 +03001931 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301932 {
Olli Etuahof119a262016-08-19 15:54:22 +03001933 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301934 resultArray = new TConstantUnion[2];
1935 float f1, f2;
1936 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1937 resultArray[0].setFConst(f1);
1938 resultArray[1].setFConst(f2);
1939 break;
1940 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301941
Olli Etuahof119a262016-08-19 15:54:22 +03001942 case EOpPackUnorm2x16:
1943 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301944 ASSERT(getType().getNominalSize() == 2);
1945 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001946 resultArray->setUConst(
1947 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301948 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301949
Olli Etuahof119a262016-08-19 15:54:22 +03001950 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301951 {
Olli Etuahof119a262016-08-19 15:54:22 +03001952 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301953 resultArray = new TConstantUnion[2];
1954 float f1, f2;
1955 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1956 resultArray[0].setFConst(f1);
1957 resultArray[1].setFConst(f2);
1958 break;
1959 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301960
Olli Etuahof119a262016-08-19 15:54:22 +03001961 case EOpPackHalf2x16:
1962 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301963 ASSERT(getType().getNominalSize() == 2);
1964 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001965 resultArray->setUConst(
1966 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301967 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301968
Olli Etuahof119a262016-08-19 15:54:22 +03001969 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301970 {
Olli Etuahof119a262016-08-19 15:54:22 +03001971 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301972 resultArray = new TConstantUnion[2];
1973 float f1, f2;
1974 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1975 resultArray[0].setFConst(f1);
1976 resultArray[1].setFConst(f2);
1977 break;
1978 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301979
Olli Etuaho25aef452017-01-29 16:15:44 -08001980 case EOpPackUnorm4x8:
1981 {
1982 ASSERT(getType().getBasicType() == EbtFloat);
1983 resultArray = new TConstantUnion();
1984 resultArray->setUConst(
1985 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1986 operandArray[2].getFConst(), operandArray[3].getFConst()));
1987 break;
1988 }
1989 case EOpPackSnorm4x8:
1990 {
1991 ASSERT(getType().getBasicType() == EbtFloat);
1992 resultArray = new TConstantUnion();
1993 resultArray->setUConst(
1994 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1995 operandArray[2].getFConst(), operandArray[3].getFConst()));
1996 break;
1997 }
1998 case EOpUnpackUnorm4x8:
1999 {
2000 ASSERT(getType().getBasicType() == EbtUInt);
2001 resultArray = new TConstantUnion[4];
2002 float f[4];
2003 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2004 for (size_t i = 0; i < 4; ++i)
2005 {
2006 resultArray[i].setFConst(f[i]);
2007 }
2008 break;
2009 }
2010 case EOpUnpackSnorm4x8:
2011 {
2012 ASSERT(getType().getBasicType() == EbtUInt);
2013 resultArray = new TConstantUnion[4];
2014 float f[4];
2015 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2016 for (size_t i = 0; i < 4; ++i)
2017 {
2018 resultArray[i].setFConst(f[i]);
2019 }
2020 break;
2021 }
2022
Olli Etuahof119a262016-08-19 15:54:22 +03002023 default:
2024 UNREACHABLE();
2025 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302026 }
2027
2028 return resultArray;
2029}
2030
Olli Etuahof119a262016-08-19 15:54:22 +03002031TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2032 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05302033{
Olli Etuahof119a262016-08-19 15:54:22 +03002034 // Do unary operations where each component of the result is computed based on the corresponding
2035 // component of the operand. Also folds normalize, though the divisor in that case takes all
2036 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05302037
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002038 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03002039 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04002040
2041 size_t objectSize = getType().getObjectSize();
2042
Arun Patoleab2b9a22015-07-06 18:27:56 +05302043 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2044 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302045 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002046 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05302047 {
Olli Etuahof119a262016-08-19 15:54:22 +03002048 case EOpNegative:
2049 switch (getType().getBasicType())
2050 {
2051 case EbtFloat:
2052 resultArray[i].setFConst(-operandArray[i].getFConst());
2053 break;
2054 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002055 if (operandArray[i] == std::numeric_limits<int>::min())
2056 {
2057 // The minimum representable integer doesn't have a positive
2058 // counterpart, rather the negation overflows and in ESSL is supposed to
2059 // wrap back to the minimum representable integer. Make sure that we
2060 // don't actually let the negation overflow, which has undefined
2061 // behavior in C++.
2062 resultArray[i].setIConst(std::numeric_limits<int>::min());
2063 }
2064 else
2065 {
2066 resultArray[i].setIConst(-operandArray[i].getIConst());
2067 }
Olli Etuahof119a262016-08-19 15:54:22 +03002068 break;
2069 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01002070 if (operandArray[i] == 0x80000000u)
2071 {
2072 resultArray[i].setUConst(0x80000000u);
2073 }
2074 else
2075 {
2076 resultArray[i].setUConst(static_cast<unsigned int>(
2077 -static_cast<int>(operandArray[i].getUConst())));
2078 }
Olli Etuahof119a262016-08-19 15:54:22 +03002079 break;
2080 default:
2081 UNREACHABLE();
2082 return nullptr;
2083 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302084 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05302085
Olli Etuahof119a262016-08-19 15:54:22 +03002086 case EOpPositive:
2087 switch (getType().getBasicType())
2088 {
2089 case EbtFloat:
2090 resultArray[i].setFConst(operandArray[i].getFConst());
2091 break;
2092 case EbtInt:
2093 resultArray[i].setIConst(operandArray[i].getIConst());
2094 break;
2095 case EbtUInt:
2096 resultArray[i].setUConst(static_cast<unsigned int>(
2097 static_cast<int>(operandArray[i].getUConst())));
2098 break;
2099 default:
2100 UNREACHABLE();
2101 return nullptr;
2102 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302103 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302104
Olli Etuahof119a262016-08-19 15:54:22 +03002105 case EOpLogicalNot:
2106 switch (getType().getBasicType())
2107 {
2108 case EbtBool:
2109 resultArray[i].setBConst(!operandArray[i].getBConst());
2110 break;
2111 default:
2112 UNREACHABLE();
2113 return nullptr;
2114 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302115 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302116
Olli Etuahof119a262016-08-19 15:54:22 +03002117 case EOpBitwiseNot:
2118 switch (getType().getBasicType())
2119 {
2120 case EbtInt:
2121 resultArray[i].setIConst(~operandArray[i].getIConst());
2122 break;
2123 case EbtUInt:
2124 resultArray[i].setUConst(~operandArray[i].getUConst());
2125 break;
2126 default:
2127 UNREACHABLE();
2128 return nullptr;
2129 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302130 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302131
Olli Etuahof119a262016-08-19 15:54:22 +03002132 case EOpRadians:
2133 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302134 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2135 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302136
Olli Etuahof119a262016-08-19 15:54:22 +03002137 case EOpDegrees:
2138 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302139 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2140 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302141
Olli Etuahof119a262016-08-19 15:54:22 +03002142 case EOpSin:
2143 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302144 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302145
Olli Etuahof119a262016-08-19 15:54:22 +03002146 case EOpCos:
2147 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2148 break;
2149
2150 case EOpTan:
2151 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2152 break;
2153
2154 case EOpAsin:
2155 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2156 // 0.
2157 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2158 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2159 diagnostics, &resultArray[i]);
2160 else
2161 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2162 break;
2163
2164 case EOpAcos:
2165 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2166 // 0.
2167 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2168 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2169 diagnostics, &resultArray[i]);
2170 else
2171 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2172 break;
2173
2174 case EOpAtan:
2175 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2176 break;
2177
2178 case EOpSinh:
2179 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2180 break;
2181
2182 case EOpCosh:
2183 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2184 break;
2185
2186 case EOpTanh:
2187 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2188 break;
2189
2190 case EOpAsinh:
2191 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2192 break;
2193
2194 case EOpAcosh:
2195 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2196 if (operandArray[i].getFConst() < 1.0f)
2197 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2198 diagnostics, &resultArray[i]);
2199 else
2200 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2201 break;
2202
2203 case EOpAtanh:
2204 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2205 // 0.
2206 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2207 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2208 diagnostics, &resultArray[i]);
2209 else
2210 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2211 break;
2212
2213 case EOpAbs:
2214 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302215 {
Olli Etuahof119a262016-08-19 15:54:22 +03002216 case EbtFloat:
2217 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2218 break;
2219 case EbtInt:
2220 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2221 break;
2222 default:
2223 UNREACHABLE();
2224 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302225 }
2226 break;
Olli Etuahof119a262016-08-19 15:54:22 +03002227
2228 case EOpSign:
2229 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05302230 {
Olli Etuahof119a262016-08-19 15:54:22 +03002231 case EbtFloat:
2232 {
2233 float fConst = operandArray[i].getFConst();
2234 float fResult = 0.0f;
2235 if (fConst > 0.0f)
2236 fResult = 1.0f;
2237 else if (fConst < 0.0f)
2238 fResult = -1.0f;
2239 resultArray[i].setFConst(fResult);
2240 break;
2241 }
2242 case EbtInt:
2243 {
2244 int iConst = operandArray[i].getIConst();
2245 int iResult = 0;
2246 if (iConst > 0)
2247 iResult = 1;
2248 else if (iConst < 0)
2249 iResult = -1;
2250 resultArray[i].setIConst(iResult);
2251 break;
2252 }
2253 default:
2254 UNREACHABLE();
2255 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302256 }
2257 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302258
Olli Etuahof119a262016-08-19 15:54:22 +03002259 case EOpFloor:
2260 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2261 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302262
Olli Etuahof119a262016-08-19 15:54:22 +03002263 case EOpTrunc:
2264 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2265 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302266
Olli Etuahof119a262016-08-19 15:54:22 +03002267 case EOpRound:
2268 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2269 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302270
Olli Etuahof119a262016-08-19 15:54:22 +03002271 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302272 {
Olli Etuahof119a262016-08-19 15:54:22 +03002273 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302274 float x = operandArray[i].getFConst();
2275 float result;
2276 float fractPart = modff(x, &result);
2277 if (fabsf(fractPart) == 0.5f)
2278 result = 2.0f * roundf(x / 2.0f);
2279 else
2280 result = roundf(x);
2281 resultArray[i].setFConst(result);
2282 break;
2283 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302284
Olli Etuahof119a262016-08-19 15:54:22 +03002285 case EOpCeil:
2286 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2287 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302288
Olli Etuahof119a262016-08-19 15:54:22 +03002289 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302290 {
Olli Etuahof119a262016-08-19 15:54:22 +03002291 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302292 float x = operandArray[i].getFConst();
2293 resultArray[i].setFConst(x - floorf(x));
2294 break;
2295 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302296
Olli Etuahof119a262016-08-19 15:54:22 +03002297 case EOpIsNan:
2298 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302299 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2300 break;
Arun Patole551279e2015-07-07 18:18:23 +05302301
Olli Etuahof119a262016-08-19 15:54:22 +03002302 case EOpIsInf:
2303 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302304 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2305 break;
Arun Patole551279e2015-07-07 18:18:23 +05302306
Olli Etuahof119a262016-08-19 15:54:22 +03002307 case EOpFloatBitsToInt:
2308 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302309 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2310 break;
Arun Patole551279e2015-07-07 18:18:23 +05302311
Olli Etuahof119a262016-08-19 15:54:22 +03002312 case EOpFloatBitsToUint:
2313 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05302314 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2315 break;
Arun Patole551279e2015-07-07 18:18:23 +05302316
Olli Etuahof119a262016-08-19 15:54:22 +03002317 case EOpIntBitsToFloat:
2318 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05302319 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2320 break;
Arun Patole551279e2015-07-07 18:18:23 +05302321
Olli Etuahof119a262016-08-19 15:54:22 +03002322 case EOpUintBitsToFloat:
2323 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05302324 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2325 break;
Arun Patole551279e2015-07-07 18:18:23 +05302326
Olli Etuahof119a262016-08-19 15:54:22 +03002327 case EOpExp:
2328 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2329 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302330
Olli Etuahof119a262016-08-19 15:54:22 +03002331 case EOpLog:
2332 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2333 if (operandArray[i].getFConst() <= 0.0f)
2334 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2335 diagnostics, &resultArray[i]);
2336 else
2337 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2338 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302339
Olli Etuahof119a262016-08-19 15:54:22 +03002340 case EOpExp2:
2341 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2342 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302343
Olli Etuahof119a262016-08-19 15:54:22 +03002344 case EOpLog2:
2345 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2346 // And log2f is not available on some plarforms like old android, so just using
2347 // log(x)/log(2) here.
2348 if (operandArray[i].getFConst() <= 0.0f)
2349 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2350 diagnostics, &resultArray[i]);
2351 else
2352 {
2353 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2354 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2355 }
2356 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302357
Olli Etuahof119a262016-08-19 15:54:22 +03002358 case EOpSqrt:
2359 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2360 if (operandArray[i].getFConst() < 0.0f)
2361 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2362 diagnostics, &resultArray[i]);
2363 else
2364 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2365 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302366
Olli Etuahof119a262016-08-19 15:54:22 +03002367 case EOpInverseSqrt:
2368 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2369 // so getting the square root first using builtin function sqrt() and then taking
2370 // its inverse.
2371 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2372 // result to 0.
2373 if (operandArray[i].getFConst() <= 0.0f)
2374 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2375 diagnostics, &resultArray[i]);
2376 else
2377 {
2378 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2379 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2380 }
2381 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302382
Olli Etuahod68924e2017-01-02 17:34:40 +00002383 case EOpLogicalNotComponentWise:
Olli Etuahof119a262016-08-19 15:54:22 +03002384 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302385 resultArray[i].setBConst(!operandArray[i].getBConst());
2386 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302387
Olli Etuahof119a262016-08-19 15:54:22 +03002388 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302389 {
Olli Etuahof119a262016-08-19 15:54:22 +03002390 ASSERT(getType().getBasicType() == EbtFloat);
2391 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302392 float length = VectorLength(operandArray, objectSize);
2393 if (length)
2394 resultArray[i].setFConst(x / length);
2395 else
Olli Etuahof119a262016-08-19 15:54:22 +03002396 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2397 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302398 break;
2399 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00002400 case EOpBitfieldReverse:
2401 {
2402 uint32_t value;
2403 if (getType().getBasicType() == EbtInt)
2404 {
2405 value = static_cast<uint32_t>(operandArray[i].getIConst());
2406 }
2407 else
2408 {
2409 ASSERT(getType().getBasicType() == EbtUInt);
2410 value = operandArray[i].getUConst();
2411 }
2412 uint32_t result = gl::BitfieldReverse(value);
2413 if (getType().getBasicType() == EbtInt)
2414 {
2415 resultArray[i].setIConst(static_cast<int32_t>(result));
2416 }
2417 else
2418 {
2419 resultArray[i].setUConst(result);
2420 }
2421 break;
2422 }
2423 case EOpBitCount:
2424 {
2425 uint32_t value;
2426 if (getType().getBasicType() == EbtInt)
2427 {
2428 value = static_cast<uint32_t>(operandArray[i].getIConst());
2429 }
2430 else
2431 {
2432 ASSERT(getType().getBasicType() == EbtUInt);
2433 value = operandArray[i].getUConst();
2434 }
2435 int result = gl::BitCount(value);
2436 resultArray[i].setIConst(result);
2437 break;
2438 }
2439 case EOpFindLSB:
2440 {
2441 uint32_t value;
2442 if (getType().getBasicType() == EbtInt)
2443 {
2444 value = static_cast<uint32_t>(operandArray[i].getIConst());
2445 }
2446 else
2447 {
2448 ASSERT(getType().getBasicType() == EbtUInt);
2449 value = operandArray[i].getUConst();
2450 }
2451 resultArray[i].setIConst(gl::FindLSB(value));
2452 break;
2453 }
2454 case EOpFindMSB:
2455 {
2456 uint32_t value;
2457 if (getType().getBasicType() == EbtInt)
2458 {
2459 int intValue = operandArray[i].getIConst();
2460 value = static_cast<uint32_t>(intValue);
2461 if (intValue < 0)
2462 {
2463 // Look for zero instead of one in value. This also handles the intValue ==
2464 // -1 special case, where the return value needs to be -1.
2465 value = ~value;
2466 }
2467 }
2468 else
2469 {
2470 ASSERT(getType().getBasicType() == EbtUInt);
2471 value = operandArray[i].getUConst();
2472 }
2473 resultArray[i].setIConst(gl::FindMSB(value));
2474 break;
2475 }
Olli Etuahof119a262016-08-19 15:54:22 +03002476 case EOpDFdx:
2477 case EOpDFdy:
2478 case EOpFwidth:
2479 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302480 // Derivatives of constant arguments should be 0.
2481 resultArray[i].setFConst(0.0f);
2482 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302483
Olli Etuahof119a262016-08-19 15:54:22 +03002484 default:
2485 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302486 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302487 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002488
Arun Patoleab2b9a22015-07-06 18:27:56 +05302489 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002490}
2491
Olli Etuahof119a262016-08-19 15:54:22 +03002492void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2493 FloatTypeUnaryFunc builtinFunc,
2494 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302495{
2496 ASSERT(builtinFunc);
2497
Olli Etuahof119a262016-08-19 15:54:22 +03002498 ASSERT(getType().getBasicType() == EbtFloat);
2499 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302500}
2501
Jamie Madillb1a85f42014-08-19 15:23:24 -04002502// static
Olli Etuahof119a262016-08-19 15:54:22 +03002503TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002504{
2505 ASSERT(aggregate->getSequence()->size() > 0u);
2506 size_t resultSize = aggregate->getType().getObjectSize();
2507 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2508 TBasicType basicType = aggregate->getBasicType();
2509
2510 size_t resultIndex = 0u;
2511
2512 if (aggregate->getSequence()->size() == 1u)
2513 {
2514 TIntermNode *argument = aggregate->getSequence()->front();
2515 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2516 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2517 // Check the special case of constructing a matrix diagonal from a single scalar,
2518 // or a vector from a single scalar.
2519 if (argumentConstant->getType().getObjectSize() == 1u)
2520 {
2521 if (aggregate->isMatrix())
2522 {
2523 int resultCols = aggregate->getType().getCols();
2524 int resultRows = aggregate->getType().getRows();
2525 for (int col = 0; col < resultCols; ++col)
2526 {
2527 for (int row = 0; row < resultRows; ++row)
2528 {
2529 if (col == row)
2530 {
2531 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2532 }
2533 else
2534 {
2535 resultArray[resultIndex].setFConst(0.0f);
2536 }
2537 ++resultIndex;
2538 }
2539 }
2540 }
2541 else
2542 {
2543 while (resultIndex < resultSize)
2544 {
2545 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2546 ++resultIndex;
2547 }
2548 }
2549 ASSERT(resultIndex == resultSize);
2550 return resultArray;
2551 }
2552 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2553 {
2554 // The special case of constructing a matrix from a matrix.
2555 int argumentCols = argumentConstant->getType().getCols();
2556 int argumentRows = argumentConstant->getType().getRows();
2557 int resultCols = aggregate->getType().getCols();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002558 int resultRows = aggregate->getType().getRows();
Olli Etuaho1d122782015-11-06 15:35:17 +02002559 for (int col = 0; col < resultCols; ++col)
2560 {
2561 for (int row = 0; row < resultRows; ++row)
2562 {
2563 if (col < argumentCols && row < argumentRows)
2564 {
2565 resultArray[resultIndex].cast(basicType,
2566 argumentUnionArray[col * argumentRows + row]);
2567 }
2568 else if (col == row)
2569 {
2570 resultArray[resultIndex].setFConst(1.0f);
2571 }
2572 else
2573 {
2574 resultArray[resultIndex].setFConst(0.0f);
2575 }
2576 ++resultIndex;
2577 }
2578 }
2579 ASSERT(resultIndex == resultSize);
2580 return resultArray;
2581 }
2582 }
2583
2584 for (TIntermNode *&argument : *aggregate->getSequence())
2585 {
2586 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2587 size_t argumentSize = argumentConstant->getType().getObjectSize();
2588 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2589 for (size_t i = 0u; i < argumentSize; ++i)
2590 {
2591 if (resultIndex >= resultSize)
2592 break;
2593 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2594 ++resultIndex;
2595 }
2596 }
2597 ASSERT(resultIndex == resultSize);
2598 return resultArray;
2599}
2600
Olli Etuahoeb7f90f2017-07-07 17:25:23 +03002601bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2602{
2603 switch (op)
2604 {
2605 case EOpAtan:
2606 case EOpPow:
2607 case EOpMod:
2608 case EOpMin:
2609 case EOpMax:
2610 case EOpClamp:
2611 case EOpMix:
2612 case EOpStep:
2613 case EOpSmoothStep:
2614 case EOpLdexp:
2615 case EOpMulMatrixComponentWise:
2616 case EOpOuterProduct:
2617 case EOpEqualComponentWise:
2618 case EOpNotEqualComponentWise:
2619 case EOpLessThanComponentWise:
2620 case EOpLessThanEqualComponentWise:
2621 case EOpGreaterThanComponentWise:
2622 case EOpGreaterThanEqualComponentWise:
2623 case EOpDistance:
2624 case EOpDot:
2625 case EOpCross:
2626 case EOpFaceforward:
2627 case EOpReflect:
2628 case EOpRefract:
2629 case EOpBitfieldExtract:
2630 case EOpBitfieldInsert:
2631 return true;
2632 default:
2633 return false;
2634 }
2635}
2636
Olli Etuaho1d122782015-11-06 15:35:17 +02002637// static
Olli Etuahof119a262016-08-19 15:54:22 +03002638TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2639 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302640{
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002641 TOperator op = aggregate->getOp();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002642 TIntermSequence *arguments = aggregate->getSequence();
2643 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2644 std::vector<const TConstantUnion *> unionArrays(argsCount);
2645 std::vector<size_t> objectSizes(argsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002646 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302647 TBasicType basicType = EbtVoid;
2648 TSourceLoc loc;
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002649 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302650 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002651 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2652 ASSERT(argConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302653
2654 if (i == 0)
2655 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002656 basicType = argConstant->getType().getBasicType();
2657 loc = argConstant->getLine();
Arun Patole274f0702015-05-05 13:33:30 +05302658 }
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002659 unionArrays[i] = argConstant->getUnionArrayPointer();
2660 objectSizes[i] = argConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002661 if (objectSizes[i] > maxObjectSize)
2662 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302663 }
2664
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002665 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302666 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08002667 for (unsigned int i = 0; i < argsCount; i++)
Arun Patole7fa33552015-06-10 15:15:18 +05302668 if (objectSizes[i] != maxObjectSize)
2669 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2670 }
Arun Patole274f0702015-05-05 13:33:30 +05302671
Olli Etuahob43846e2015-06-02 18:18:57 +03002672 TConstantUnion *resultArray = nullptr;
Olli Etuaho51182ab2017-01-22 00:12:29 +00002673
2674 switch (op)
Arun Patole274f0702015-05-05 13:33:30 +05302675 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002676 case EOpAtan:
Arun Patole274f0702015-05-05 13:33:30 +05302677 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002678 ASSERT(basicType == EbtFloat);
2679 resultArray = new TConstantUnion[maxObjectSize];
2680 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302681 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002682 float y = unionArrays[0][i].getFConst();
2683 float x = unionArrays[1][i].getFConst();
2684 // Results are undefined if x and y are both 0.
2685 if (x == 0.0f && y == 0.0f)
2686 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2687 else
2688 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302689 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002690 break;
2691 }
Arun Patolebf790422015-05-18 17:53:04 +05302692
Olli Etuaho51182ab2017-01-22 00:12:29 +00002693 case EOpPow:
2694 {
2695 ASSERT(basicType == EbtFloat);
2696 resultArray = new TConstantUnion[maxObjectSize];
2697 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302698 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002699 float x = unionArrays[0][i].getFConst();
2700 float y = unionArrays[1][i].getFConst();
2701 // Results are undefined if x < 0.
2702 // Results are undefined if x = 0 and y <= 0.
2703 if (x < 0.0f)
2704 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2705 else if (x == 0.0f && y <= 0.0f)
2706 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2707 else
2708 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302709 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002710 break;
2711 }
Arun Patolebf790422015-05-18 17:53:04 +05302712
Olli Etuaho51182ab2017-01-22 00:12:29 +00002713 case EOpMod:
2714 {
2715 ASSERT(basicType == EbtFloat);
2716 resultArray = new TConstantUnion[maxObjectSize];
2717 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302718 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002719 float x = unionArrays[0][i].getFConst();
2720 float y = unionArrays[1][i].getFConst();
2721 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302722 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002723 break;
2724 }
Arun Patolebf790422015-05-18 17:53:04 +05302725
Olli Etuaho51182ab2017-01-22 00:12:29 +00002726 case EOpMin:
2727 {
2728 resultArray = new TConstantUnion[maxObjectSize];
2729 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302730 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002731 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302732 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002733 case EbtFloat:
2734 resultArray[i].setFConst(
2735 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2736 break;
2737 case EbtInt:
2738 resultArray[i].setIConst(
2739 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2740 break;
2741 case EbtUInt:
2742 resultArray[i].setUConst(
2743 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2744 break;
2745 default:
2746 UNREACHABLE();
2747 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302748 }
2749 }
2750 break;
Arun Patole274f0702015-05-05 13:33:30 +05302751 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002752
2753 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302754 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002755 resultArray = new TConstantUnion[maxObjectSize];
2756 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patole274f0702015-05-05 13:33:30 +05302757 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002758 switch (basicType)
Arun Patole274f0702015-05-05 13:33:30 +05302759 {
Olli Etuaho51182ab2017-01-22 00:12:29 +00002760 case EbtFloat:
2761 resultArray[i].setFConst(
2762 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2763 break;
2764 case EbtInt:
2765 resultArray[i].setIConst(
2766 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2767 break;
2768 case EbtUInt:
2769 resultArray[i].setUConst(
2770 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2771 break;
2772 default:
2773 UNREACHABLE();
2774 break;
Arun Patole274f0702015-05-05 13:33:30 +05302775 }
2776 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002777 break;
Arun Patole274f0702015-05-05 13:33:30 +05302778 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00002779
2780 case EOpStep:
2781 {
2782 ASSERT(basicType == EbtFloat);
2783 resultArray = new TConstantUnion[maxObjectSize];
2784 for (size_t i = 0; i < maxObjectSize; i++)
2785 resultArray[i].setFConst(
2786 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2787 break;
2788 }
2789
2790 case EOpLessThanComponentWise:
2791 {
2792 resultArray = new TConstantUnion[maxObjectSize];
2793 for (size_t i = 0; i < maxObjectSize; i++)
2794 {
2795 switch (basicType)
2796 {
2797 case EbtFloat:
2798 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2799 unionArrays[1][i].getFConst());
2800 break;
2801 case EbtInt:
2802 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2803 unionArrays[1][i].getIConst());
2804 break;
2805 case EbtUInt:
2806 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2807 unionArrays[1][i].getUConst());
2808 break;
2809 default:
2810 UNREACHABLE();
2811 break;
2812 }
2813 }
2814 break;
2815 }
2816
2817 case EOpLessThanEqualComponentWise:
2818 {
2819 resultArray = new TConstantUnion[maxObjectSize];
2820 for (size_t i = 0; i < maxObjectSize; i++)
2821 {
2822 switch (basicType)
2823 {
2824 case EbtFloat:
2825 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2826 unionArrays[1][i].getFConst());
2827 break;
2828 case EbtInt:
2829 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2830 unionArrays[1][i].getIConst());
2831 break;
2832 case EbtUInt:
2833 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2834 unionArrays[1][i].getUConst());
2835 break;
2836 default:
2837 UNREACHABLE();
2838 break;
2839 }
2840 }
2841 break;
2842 }
2843
2844 case EOpGreaterThanComponentWise:
2845 {
2846 resultArray = new TConstantUnion[maxObjectSize];
2847 for (size_t i = 0; i < maxObjectSize; i++)
2848 {
2849 switch (basicType)
2850 {
2851 case EbtFloat:
2852 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2853 unionArrays[1][i].getFConst());
2854 break;
2855 case EbtInt:
2856 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2857 unionArrays[1][i].getIConst());
2858 break;
2859 case EbtUInt:
2860 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2861 unionArrays[1][i].getUConst());
2862 break;
2863 default:
2864 UNREACHABLE();
2865 break;
2866 }
2867 }
2868 break;
2869 }
2870 case EOpGreaterThanEqualComponentWise:
2871 {
2872 resultArray = new TConstantUnion[maxObjectSize];
2873 for (size_t i = 0; i < maxObjectSize; i++)
2874 {
2875 switch (basicType)
2876 {
2877 case EbtFloat:
2878 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2879 unionArrays[1][i].getFConst());
2880 break;
2881 case EbtInt:
2882 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2883 unionArrays[1][i].getIConst());
2884 break;
2885 case EbtUInt:
2886 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2887 unionArrays[1][i].getUConst());
2888 break;
2889 default:
2890 UNREACHABLE();
2891 break;
2892 }
2893 }
2894 }
2895 break;
2896
2897 case EOpEqualComponentWise:
2898 {
2899 resultArray = new TConstantUnion[maxObjectSize];
2900 for (size_t i = 0; i < maxObjectSize; i++)
2901 {
2902 switch (basicType)
2903 {
2904 case EbtFloat:
2905 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2906 unionArrays[1][i].getFConst());
2907 break;
2908 case EbtInt:
2909 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2910 unionArrays[1][i].getIConst());
2911 break;
2912 case EbtUInt:
2913 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2914 unionArrays[1][i].getUConst());
2915 break;
2916 case EbtBool:
2917 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2918 unionArrays[1][i].getBConst());
2919 break;
2920 default:
2921 UNREACHABLE();
2922 break;
2923 }
2924 }
2925 break;
2926 }
2927
2928 case EOpNotEqualComponentWise:
2929 {
2930 resultArray = new TConstantUnion[maxObjectSize];
2931 for (size_t i = 0; i < maxObjectSize; i++)
2932 {
2933 switch (basicType)
2934 {
2935 case EbtFloat:
2936 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2937 unionArrays[1][i].getFConst());
2938 break;
2939 case EbtInt:
2940 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2941 unionArrays[1][i].getIConst());
2942 break;
2943 case EbtUInt:
2944 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2945 unionArrays[1][i].getUConst());
2946 break;
2947 case EbtBool:
2948 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2949 unionArrays[1][i].getBConst());
2950 break;
2951 default:
2952 UNREACHABLE();
2953 break;
2954 }
2955 }
2956 break;
2957 }
2958
2959 case EOpDistance:
2960 {
2961 ASSERT(basicType == EbtFloat);
2962 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2963 resultArray = new TConstantUnion();
2964 for (size_t i = 0; i < maxObjectSize; i++)
2965 {
2966 float x = unionArrays[0][i].getFConst();
2967 float y = unionArrays[1][i].getFConst();
2968 distanceArray[i].setFConst(x - y);
2969 }
2970 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2971 break;
2972 }
2973
2974 case EOpDot:
2975 ASSERT(basicType == EbtFloat);
2976 resultArray = new TConstantUnion();
2977 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2978 break;
2979
2980 case EOpCross:
2981 {
2982 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2983 resultArray = new TConstantUnion[maxObjectSize];
2984 float x0 = unionArrays[0][0].getFConst();
2985 float x1 = unionArrays[0][1].getFConst();
2986 float x2 = unionArrays[0][2].getFConst();
2987 float y0 = unionArrays[1][0].getFConst();
2988 float y1 = unionArrays[1][1].getFConst();
2989 float y2 = unionArrays[1][2].getFConst();
2990 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2991 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2992 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2993 break;
2994 }
2995
2996 case EOpReflect:
2997 {
2998 ASSERT(basicType == EbtFloat);
2999 // genType reflect (genType I, genType N) :
3000 // For the incident vector I and surface orientation N, returns the reflection
3001 // direction:
3002 // I - 2 * dot(N, I) * N.
3003 resultArray = new TConstantUnion[maxObjectSize];
3004 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3005 for (size_t i = 0; i < maxObjectSize; i++)
3006 {
3007 float result = unionArrays[0][i].getFConst() -
3008 2.0f * dotProduct * unionArrays[1][i].getFConst();
3009 resultArray[i].setFConst(result);
3010 }
3011 break;
3012 }
3013
3014 case EOpMulMatrixComponentWise:
3015 {
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003016 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3017 (*arguments)[1]->getAsTyped()->isMatrix());
Olli Etuaho51182ab2017-01-22 00:12:29 +00003018 // Perform component-wise matrix multiplication.
3019 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003020 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003021 angle::Matrix<float> result =
3022 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3023 SetUnionArrayFromMatrix(result, resultArray);
3024 break;
3025 }
3026
3027 case EOpOuterProduct:
3028 {
3029 ASSERT(basicType == EbtFloat);
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003030 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3031 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003032 resultArray = new TConstantUnion[numRows * numCols];
3033 angle::Matrix<float> result =
3034 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3035 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3036 SetUnionArrayFromMatrix(result, resultArray);
3037 break;
3038 }
3039
3040 case EOpClamp:
3041 {
3042 resultArray = new TConstantUnion[maxObjectSize];
3043 for (size_t i = 0; i < maxObjectSize; i++)
3044 {
3045 switch (basicType)
3046 {
3047 case EbtFloat:
3048 {
3049 float x = unionArrays[0][i].getFConst();
3050 float min = unionArrays[1][i].getFConst();
3051 float max = unionArrays[2][i].getFConst();
3052 // Results are undefined if min > max.
3053 if (min > max)
3054 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3055 &resultArray[i]);
3056 else
3057 resultArray[i].setFConst(gl::clamp(x, min, max));
3058 break;
3059 }
3060
3061 case EbtInt:
3062 {
3063 int x = unionArrays[0][i].getIConst();
3064 int min = unionArrays[1][i].getIConst();
3065 int max = unionArrays[2][i].getIConst();
3066 // Results are undefined if min > max.
3067 if (min > max)
3068 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3069 &resultArray[i]);
3070 else
3071 resultArray[i].setIConst(gl::clamp(x, min, max));
3072 break;
3073 }
3074 case EbtUInt:
3075 {
3076 unsigned int x = unionArrays[0][i].getUConst();
3077 unsigned int min = unionArrays[1][i].getUConst();
3078 unsigned int max = unionArrays[2][i].getUConst();
3079 // Results are undefined if min > max.
3080 if (min > max)
3081 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3082 &resultArray[i]);
3083 else
3084 resultArray[i].setUConst(gl::clamp(x, min, max));
3085 break;
3086 }
3087 default:
3088 UNREACHABLE();
3089 break;
3090 }
3091 }
3092 break;
3093 }
3094
3095 case EOpMix:
3096 {
3097 ASSERT(basicType == EbtFloat);
3098 resultArray = new TConstantUnion[maxObjectSize];
3099 for (size_t i = 0; i < maxObjectSize; i++)
3100 {
3101 float x = unionArrays[0][i].getFConst();
3102 float y = unionArrays[1][i].getFConst();
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -08003103 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
Olli Etuaho51182ab2017-01-22 00:12:29 +00003104 if (type == EbtFloat)
3105 {
3106 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3107 float a = unionArrays[2][i].getFConst();
3108 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3109 }
3110 else // 3rd parameter is EbtBool
3111 {
3112 ASSERT(type == EbtBool);
3113 // Selects which vector each returned component comes from.
3114 // For a component of a that is false, the corresponding component of x is
3115 // returned.
3116 // For a component of a that is true, the corresponding component of y is
3117 // returned.
3118 bool a = unionArrays[2][i].getBConst();
3119 resultArray[i].setFConst(a ? y : x);
3120 }
3121 }
3122 break;
3123 }
3124
3125 case EOpSmoothStep:
3126 {
3127 ASSERT(basicType == EbtFloat);
3128 resultArray = new TConstantUnion[maxObjectSize];
3129 for (size_t i = 0; i < maxObjectSize; i++)
3130 {
3131 float edge0 = unionArrays[0][i].getFConst();
3132 float edge1 = unionArrays[1][i].getFConst();
3133 float x = unionArrays[2][i].getFConst();
3134 // Results are undefined if edge0 >= edge1.
3135 if (edge0 >= edge1)
3136 {
3137 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3138 }
3139 else
3140 {
3141 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3142 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3143 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3144 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3145 }
3146 }
3147 break;
3148 }
3149
Olli Etuaho74da73f2017-02-01 15:37:48 +00003150 case EOpLdexp:
3151 {
3152 resultArray = new TConstantUnion[maxObjectSize];
3153 for (size_t i = 0; i < maxObjectSize; i++)
3154 {
3155 float x = unionArrays[0][i].getFConst();
3156 int exp = unionArrays[1][i].getIConst();
3157 if (exp > 128)
3158 {
3159 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3160 }
3161 else
3162 {
3163 resultArray[i].setFConst(gl::Ldexp(x, exp));
3164 }
3165 }
3166 break;
3167 }
3168
Jamie Madille72595b2017-06-06 15:12:26 -04003169 case EOpFaceforward:
Olli Etuaho51182ab2017-01-22 00:12:29 +00003170 {
3171 ASSERT(basicType == EbtFloat);
3172 // genType faceforward(genType N, genType I, genType Nref) :
3173 // If dot(Nref, I) < 0 return N, otherwise return -N.
3174 resultArray = new TConstantUnion[maxObjectSize];
3175 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3176 for (size_t i = 0; i < maxObjectSize; i++)
3177 {
3178 if (dotProduct < 0)
3179 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3180 else
3181 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3182 }
3183 break;
3184 }
3185
3186 case EOpRefract:
3187 {
3188 ASSERT(basicType == EbtFloat);
3189 // genType refract(genType I, genType N, float eta) :
3190 // For the incident vector I and surface normal N, and the ratio of indices of
3191 // refraction eta,
3192 // return the refraction vector. The result is computed by
3193 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3194 // if (k < 0.0)
3195 // return genType(0.0)
3196 // else
3197 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3198 resultArray = new TConstantUnion[maxObjectSize];
3199 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3200 for (size_t i = 0; i < maxObjectSize; i++)
3201 {
3202 float eta = unionArrays[2][i].getFConst();
3203 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3204 if (k < 0.0f)
3205 resultArray[i].setFConst(0.0f);
3206 else
3207 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3208 (eta * dotProduct + sqrtf(k)) *
3209 unionArrays[1][i].getFConst());
3210 }
3211 break;
3212 }
Olli Etuaho9250cb22017-01-21 10:51:27 +00003213 case EOpBitfieldExtract:
3214 {
3215 resultArray = new TConstantUnion[maxObjectSize];
3216 for (size_t i = 0; i < maxObjectSize; ++i)
3217 {
3218 int offset = unionArrays[1][0].getIConst();
3219 int bits = unionArrays[2][0].getIConst();
3220 if (bits == 0)
3221 {
3222 if (aggregate->getBasicType() == EbtInt)
3223 {
3224 resultArray[i].setIConst(0);
3225 }
3226 else
3227 {
3228 ASSERT(aggregate->getBasicType() == EbtUInt);
3229 resultArray[i].setUConst(0);
3230 }
3231 }
3232 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3233 {
3234 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3235 &resultArray[i]);
3236 }
3237 else
3238 {
3239 // bits can be 32 here, so we need to avoid bit shift overflow.
3240 uint32_t maskMsb = 1u << (bits - 1);
3241 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3242 if (aggregate->getBasicType() == EbtInt)
3243 {
3244 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3245 uint32_t resultUnsigned = (value & mask) >> offset;
3246 if ((resultUnsigned & maskMsb) != 0)
3247 {
3248 // The most significant bits (from bits+1 to the most significant bit)
3249 // should be set to 1.
3250 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3251 resultUnsigned |= higherBitsMask;
3252 }
3253 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3254 }
3255 else
3256 {
3257 ASSERT(aggregate->getBasicType() == EbtUInt);
3258 uint32_t value = unionArrays[0][i].getUConst();
3259 resultArray[i].setUConst((value & mask) >> offset);
3260 }
3261 }
3262 }
3263 break;
3264 }
3265 case EOpBitfieldInsert:
3266 {
3267 resultArray = new TConstantUnion[maxObjectSize];
3268 for (size_t i = 0; i < maxObjectSize; ++i)
3269 {
3270 int offset = unionArrays[2][0].getIConst();
3271 int bits = unionArrays[3][0].getIConst();
3272 if (bits == 0)
3273 {
3274 if (aggregate->getBasicType() == EbtInt)
3275 {
3276 int32_t base = unionArrays[0][i].getIConst();
3277 resultArray[i].setIConst(base);
3278 }
3279 else
3280 {
3281 ASSERT(aggregate->getBasicType() == EbtUInt);
3282 uint32_t base = unionArrays[0][i].getUConst();
3283 resultArray[i].setUConst(base);
3284 }
3285 }
3286 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3287 {
3288 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3289 &resultArray[i]);
3290 }
3291 else
3292 {
3293 // bits can be 32 here, so we need to avoid bit shift overflow.
3294 uint32_t maskMsb = 1u << (bits - 1);
3295 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3296 uint32_t baseMask = ~insertMask;
3297 if (aggregate->getBasicType() == EbtInt)
3298 {
3299 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3300 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3301 uint32_t resultUnsigned =
3302 (base & baseMask) | ((insert << offset) & insertMask);
3303 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3304 }
3305 else
3306 {
3307 ASSERT(aggregate->getBasicType() == EbtUInt);
3308 uint32_t base = unionArrays[0][i].getUConst();
3309 uint32_t insert = unionArrays[1][i].getUConst();
3310 resultArray[i].setUConst((base & baseMask) |
3311 ((insert << offset) & insertMask));
3312 }
3313 }
3314 }
3315 break;
3316 }
Olli Etuaho51182ab2017-01-22 00:12:29 +00003317
3318 default:
3319 UNREACHABLE();
3320 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05303321 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003322 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05303323}
3324
Jamie Madill45bcc782016-11-07 13:58:48 -05003325} // namespace sh