blob: 4a60dc5e46eb0a75d2dac885dba532e47bffe80b [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>
16
17#include "compiler/translator/HashNames.h"
18#include "compiler/translator/IntermNode.h"
19#include "compiler/translator/SymbolTable.h"
20
21namespace
22{
23
Arun Patole9dea48f2015-04-02 11:45:09 +053024const float kPi = 3.14159265358979323846f;
25const float kDegreesToRadiansMultiplier = kPi / 180.0f;
26const float kRadiansToDegreesMultiplier = 180.0f / kPi;
27
Jamie Madillb1a85f42014-08-19 15:23:24 -040028TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
29{
30 return left > right ? left : right;
31}
32
33bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
34{
35 switch (op)
36 {
37 case EOpMul:
38 case EOpMulAssign:
39 return left.getNominalSize() == right.getNominalSize() &&
40 left.getSecondarySize() == right.getSecondarySize();
41 case EOpVectorTimesScalar:
42 case EOpVectorTimesScalarAssign:
43 return true;
44 case EOpVectorTimesMatrix:
45 return left.getNominalSize() == right.getRows();
46 case EOpVectorTimesMatrixAssign:
47 return left.getNominalSize() == right.getRows() &&
48 left.getNominalSize() == right.getCols();
49 case EOpMatrixTimesVector:
50 return left.getCols() == right.getNominalSize();
51 case EOpMatrixTimesScalar:
52 case EOpMatrixTimesScalarAssign:
53 return true;
54 case EOpMatrixTimesMatrix:
55 return left.getCols() == right.getRows();
56 case EOpMatrixTimesMatrixAssign:
57 return left.getCols() == right.getCols() &&
58 left.getRows() == right.getRows();
59
60 default:
61 UNREACHABLE();
62 return false;
63 }
64}
65
66bool CompareStructure(const TType& leftNodeType,
67 ConstantUnion *rightUnionArray,
68 ConstantUnion *leftUnionArray);
69
70bool CompareStruct(const TType &leftNodeType,
71 ConstantUnion *rightUnionArray,
72 ConstantUnion *leftUnionArray)
73{
74 const TFieldList &fields = leftNodeType.getStruct()->fields();
75
76 size_t structSize = fields.size();
77 size_t index = 0;
78
79 for (size_t j = 0; j < structSize; j++)
80 {
81 size_t size = fields[j]->type()->getObjectSize();
82 for (size_t i = 0; i < size; i++)
83 {
84 if (fields[j]->type()->getBasicType() == EbtStruct)
85 {
86 if (!CompareStructure(*fields[j]->type(),
87 &rightUnionArray[index],
88 &leftUnionArray[index]))
89 {
90 return false;
91 }
92 }
93 else
94 {
95 if (leftUnionArray[index] != rightUnionArray[index])
96 return false;
97 index++;
98 }
99 }
100 }
101 return true;
102}
103
104bool CompareStructure(const TType &leftNodeType,
105 ConstantUnion *rightUnionArray,
106 ConstantUnion *leftUnionArray)
107{
108 if (leftNodeType.isArray())
109 {
110 TType typeWithoutArrayness = leftNodeType;
111 typeWithoutArrayness.clearArrayness();
112
113 size_t arraySize = leftNodeType.getArraySize();
114
115 for (size_t i = 0; i < arraySize; ++i)
116 {
117 size_t offset = typeWithoutArrayness.getObjectSize() * i;
118 if (!CompareStruct(typeWithoutArrayness,
119 &rightUnionArray[offset],
120 &leftUnionArray[offset]))
121 {
122 return false;
123 }
124 }
125 }
126 else
127 {
128 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
129 }
130 return true;
131}
132
133} // namespace anonymous
134
135
136////////////////////////////////////////////////////////////////
137//
138// Member functions of the nodes used for building the tree.
139//
140////////////////////////////////////////////////////////////////
141
Olli Etuahod2a67b92014-10-21 16:42:57 +0300142void TIntermTyped::setTypePreservePrecision(const TType &t)
143{
144 TPrecision precision = getPrecision();
145 mType = t;
146 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
147 mType.setPrecision(precision);
148}
149
Jamie Madillb1a85f42014-08-19 15:23:24 -0400150#define REPLACE_IF_IS(node, type, original, replacement) \
151 if (node == original) { \
152 node = static_cast<type *>(replacement); \
153 return true; \
154 }
155
156bool TIntermLoop::replaceChildNode(
157 TIntermNode *original, TIntermNode *replacement)
158{
159 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
160 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
161 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
162 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
163 return false;
164}
165
Jamie Madillb1a85f42014-08-19 15:23:24 -0400166bool TIntermBranch::replaceChildNode(
167 TIntermNode *original, TIntermNode *replacement)
168{
169 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
170 return false;
171}
172
Jamie Madillb1a85f42014-08-19 15:23:24 -0400173bool TIntermBinary::replaceChildNode(
174 TIntermNode *original, TIntermNode *replacement)
175{
176 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
177 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
178 return false;
179}
180
Jamie Madillb1a85f42014-08-19 15:23:24 -0400181bool TIntermUnary::replaceChildNode(
182 TIntermNode *original, TIntermNode *replacement)
183{
184 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
185 return false;
186}
187
Jamie Madillb1a85f42014-08-19 15:23:24 -0400188bool TIntermAggregate::replaceChildNode(
189 TIntermNode *original, TIntermNode *replacement)
190{
191 for (size_t ii = 0; ii < mSequence.size(); ++ii)
192 {
193 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
194 }
195 return false;
196}
197
Olli Etuahod2a67b92014-10-21 16:42:57 +0300198void TIntermAggregate::setPrecisionFromChildren()
199{
200 if (getBasicType() == EbtBool)
201 {
202 mType.setPrecision(EbpUndefined);
203 return;
204 }
205
206 TPrecision precision = EbpUndefined;
207 TIntermSequence::iterator childIter = mSequence.begin();
208 while (childIter != mSequence.end())
209 {
210 TIntermTyped *typed = (*childIter)->getAsTyped();
211 if (typed)
212 precision = GetHigherPrecision(typed->getPrecision(), precision);
213 ++childIter;
214 }
215 mType.setPrecision(precision);
216}
217
218void TIntermAggregate::setBuiltInFunctionPrecision()
219{
220 // All built-ins returning bool should be handled as ops, not functions.
221 ASSERT(getBasicType() != EbtBool);
222
223 TPrecision precision = EbpUndefined;
224 TIntermSequence::iterator childIter = mSequence.begin();
225 while (childIter != mSequence.end())
226 {
227 TIntermTyped *typed = (*childIter)->getAsTyped();
228 // ESSL spec section 8: texture functions get their precision from the sampler.
229 if (typed && IsSampler(typed->getBasicType()))
230 {
231 precision = typed->getPrecision();
232 break;
233 }
234 ++childIter;
235 }
236 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
237 // All other functions that take a sampler are assumed to be texture functions.
238 if (mName.find("textureSize") == 0)
239 mType.setPrecision(EbpHigh);
240 else
241 mType.setPrecision(precision);
242}
243
Jamie Madillb1a85f42014-08-19 15:23:24 -0400244bool TIntermSelection::replaceChildNode(
245 TIntermNode *original, TIntermNode *replacement)
246{
247 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
248 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
249 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
250 return false;
251}
252
Olli Etuahoa3a36662015-02-17 13:46:51 +0200253bool TIntermSwitch::replaceChildNode(
254 TIntermNode *original, TIntermNode *replacement)
255{
256 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
257 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
258 return false;
259}
260
261bool TIntermCase::replaceChildNode(
262 TIntermNode *original, TIntermNode *replacement)
263{
264 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
265 return false;
266}
267
Jamie Madillb1a85f42014-08-19 15:23:24 -0400268//
269// Say whether or not an operation node changes the value of a variable.
270//
271bool TIntermOperator::isAssignment() const
272{
273 switch (mOp)
274 {
275 case EOpPostIncrement:
276 case EOpPostDecrement:
277 case EOpPreIncrement:
278 case EOpPreDecrement:
279 case EOpAssign:
280 case EOpAddAssign:
281 case EOpSubAssign:
282 case EOpMulAssign:
283 case EOpVectorTimesMatrixAssign:
284 case EOpVectorTimesScalarAssign:
285 case EOpMatrixTimesScalarAssign:
286 case EOpMatrixTimesMatrixAssign:
287 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200288 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200289 case EOpBitShiftLeftAssign:
290 case EOpBitShiftRightAssign:
291 case EOpBitwiseAndAssign:
292 case EOpBitwiseXorAssign:
293 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400294 return true;
295 default:
296 return false;
297 }
298}
299
300//
301// returns true if the operator is for one of the constructors
302//
303bool TIntermOperator::isConstructor() const
304{
305 switch (mOp)
306 {
307 case EOpConstructVec2:
308 case EOpConstructVec3:
309 case EOpConstructVec4:
310 case EOpConstructMat2:
311 case EOpConstructMat3:
312 case EOpConstructMat4:
313 case EOpConstructFloat:
314 case EOpConstructIVec2:
315 case EOpConstructIVec3:
316 case EOpConstructIVec4:
317 case EOpConstructInt:
318 case EOpConstructUVec2:
319 case EOpConstructUVec3:
320 case EOpConstructUVec4:
321 case EOpConstructUInt:
322 case EOpConstructBVec2:
323 case EOpConstructBVec3:
324 case EOpConstructBVec4:
325 case EOpConstructBool:
326 case EOpConstructStruct:
327 return true;
328 default:
329 return false;
330 }
331}
332
333//
334// Make sure the type of a unary operator is appropriate for its
335// combination of operation and operand type.
336//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200337void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400338{
339 switch (mOp)
340 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200341 case EOpFloatBitsToInt:
342 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200343 case EOpIntBitsToFloat:
344 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200345 case EOpPackSnorm2x16:
346 case EOpPackUnorm2x16:
347 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200348 case EOpUnpackSnorm2x16:
349 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200350 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530351 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200352 case EOpUnpackHalf2x16:
353 mType.setPrecision(EbpMedium);
354 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400355 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200356 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400357 }
358
Olli Etuahof6c694b2015-03-26 14:50:53 +0200359 if (funcReturnType != nullptr)
360 {
361 if (funcReturnType->getBasicType() == EbtBool)
362 {
363 // Bool types should not have precision.
364 setType(*funcReturnType);
365 }
366 else
367 {
368 // Precision of the node has been set based on the operand.
369 setTypePreservePrecision(*funcReturnType);
370 }
371 }
372
Jamie Madillb1a85f42014-08-19 15:23:24 -0400373 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400374}
375
376//
377// Establishes the type of the resultant operation, as well as
378// makes the operator the correct one for the operands.
379//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200380// For lots of operations it should already be established that the operand
381// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400382//
383bool TIntermBinary::promote(TInfoSink &infoSink)
384{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200385 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400386
Jamie Madillb1a85f42014-08-19 15:23:24 -0400387 //
388 // Base assumption: just make the type the same as the left
389 // operand. Then only deviations from this need be coded.
390 //
391 setType(mLeft->getType());
392
393 // The result gets promoted to the highest precision.
394 TPrecision higherPrecision = GetHigherPrecision(
395 mLeft->getPrecision(), mRight->getPrecision());
396 getTypePointer()->setPrecision(higherPrecision);
397
398 // Binary operations results in temporary variables unless both
399 // operands are const.
400 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
401 {
402 getTypePointer()->setQualifier(EvqTemporary);
403 }
404
405 const int nominalSize =
406 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
407
408 //
409 // All scalars or structs. Code after this test assumes this case is removed!
410 //
411 if (nominalSize == 1)
412 {
413 switch (mOp)
414 {
415 //
416 // Promote to conditional
417 //
418 case EOpEqual:
419 case EOpNotEqual:
420 case EOpLessThan:
421 case EOpGreaterThan:
422 case EOpLessThanEqual:
423 case EOpGreaterThanEqual:
424 setType(TType(EbtBool, EbpUndefined));
425 break;
426
427 //
428 // And and Or operate on conditionals
429 //
430 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200431 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400432 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200433 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400434 setType(TType(EbtBool, EbpUndefined));
435 break;
436
437 default:
438 break;
439 }
440 return true;
441 }
442
443 // If we reach here, at least one of the operands is vector or matrix.
444 // The other operand could be a scalar, vector, or matrix.
445 // Can these two operands be combined?
446 //
447 TBasicType basicType = mLeft->getBasicType();
448 switch (mOp)
449 {
450 case EOpMul:
451 if (!mLeft->isMatrix() && mRight->isMatrix())
452 {
453 if (mLeft->isVector())
454 {
455 mOp = EOpVectorTimesMatrix;
456 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700457 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400458 }
459 else
460 {
461 mOp = EOpMatrixTimesScalar;
462 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700463 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400464 }
465 }
466 else if (mLeft->isMatrix() && !mRight->isMatrix())
467 {
468 if (mRight->isVector())
469 {
470 mOp = EOpMatrixTimesVector;
471 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700472 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400473 }
474 else
475 {
476 mOp = EOpMatrixTimesScalar;
477 }
478 }
479 else if (mLeft->isMatrix() && mRight->isMatrix())
480 {
481 mOp = EOpMatrixTimesMatrix;
482 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700483 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400484 }
485 else if (!mLeft->isMatrix() && !mRight->isMatrix())
486 {
487 if (mLeft->isVector() && mRight->isVector())
488 {
489 // leave as component product
490 }
491 else if (mLeft->isVector() || mRight->isVector())
492 {
493 mOp = EOpVectorTimesScalar;
494 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700495 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400496 }
497 }
498 else
499 {
500 infoSink.info.message(EPrefixInternalError, getLine(),
501 "Missing elses");
502 return false;
503 }
504
505 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
506 {
507 return false;
508 }
509 break;
510
511 case EOpMulAssign:
512 if (!mLeft->isMatrix() && mRight->isMatrix())
513 {
514 if (mLeft->isVector())
515 {
516 mOp = EOpVectorTimesMatrixAssign;
517 }
518 else
519 {
520 return false;
521 }
522 }
523 else if (mLeft->isMatrix() && !mRight->isMatrix())
524 {
525 if (mRight->isVector())
526 {
527 return false;
528 }
529 else
530 {
531 mOp = EOpMatrixTimesScalarAssign;
532 }
533 }
534 else if (mLeft->isMatrix() && mRight->isMatrix())
535 {
536 mOp = EOpMatrixTimesMatrixAssign;
537 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700538 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400539 }
540 else if (!mLeft->isMatrix() && !mRight->isMatrix())
541 {
542 if (mLeft->isVector() && mRight->isVector())
543 {
544 // leave as component product
545 }
546 else if (mLeft->isVector() || mRight->isVector())
547 {
548 if (!mLeft->isVector())
549 return false;
550 mOp = EOpVectorTimesScalarAssign;
551 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700552 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400553 }
554 }
555 else
556 {
557 infoSink.info.message(EPrefixInternalError, getLine(),
558 "Missing elses");
559 return false;
560 }
561
562 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
563 {
564 return false;
565 }
566 break;
567
568 case EOpAssign:
569 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200570 // No more additional checks are needed.
571 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
572 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
573 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400574 case EOpAdd:
575 case EOpSub:
576 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200577 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200578 case EOpBitShiftLeft:
579 case EOpBitShiftRight:
580 case EOpBitwiseAnd:
581 case EOpBitwiseXor:
582 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400583 case EOpAddAssign:
584 case EOpSubAssign:
585 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200586 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200587 case EOpBitShiftLeftAssign:
588 case EOpBitShiftRightAssign:
589 case EOpBitwiseAndAssign:
590 case EOpBitwiseXorAssign:
591 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400592 if ((mLeft->isMatrix() && mRight->isVector()) ||
593 (mLeft->isVector() && mRight->isMatrix()))
594 {
595 return false;
596 }
597
598 // Are the sizes compatible?
599 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
600 mLeft->getSecondarySize() != mRight->getSecondarySize())
601 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200602 // If the nominal sizes of operands do not match:
603 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400604 if (!mLeft->isScalar() && !mRight->isScalar())
605 return false;
606
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200607 // In the case of compound assignment other than multiply-assign,
608 // the right side needs to be a scalar. Otherwise a vector/matrix
609 // would be assigned to a scalar. A scalar can't be shifted by a
610 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200611 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200612 (isAssignment() ||
613 mOp == EOpBitShiftLeft ||
614 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200615 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400616 }
617
618 {
619 const int secondarySize = std::max(
620 mLeft->getSecondarySize(), mRight->getSecondarySize());
621 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700622 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200623 if (mLeft->isArray())
624 {
625 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
626 mType.setArraySize(mLeft->getArraySize());
627 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400628 }
629 break;
630
631 case EOpEqual:
632 case EOpNotEqual:
633 case EOpLessThan:
634 case EOpGreaterThan:
635 case EOpLessThanEqual:
636 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200637 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
638 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400639 setType(TType(EbtBool, EbpUndefined));
640 break;
641
642 default:
643 return false;
644 }
645 return true;
646}
647
648//
649// The fold functions see if an operation on a constant can be done in place,
650// without generating run-time code.
651//
652// Returns the node to keep using, which may or may not be the node passed in.
653//
654TIntermTyped *TIntermConstantUnion::fold(
655 TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink)
656{
657 ConstantUnion *unionArray = getUnionArrayPointer();
658
659 if (!unionArray)
Jamie Madillb7757782015-04-14 15:29:29 +0000660 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400661
662 size_t objectSize = getType().getObjectSize();
663
664 if (constantNode)
665 {
666 // binary operations
667 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
668 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
669 TType returnType = getType();
670
671 if (!rightUnionArray)
Jamie Madillb7757782015-04-14 15:29:29 +0000672 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400673
674 // for a case like float f = 1.2 + vec4(2,3,4,5);
675 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1)
676 {
677 rightUnionArray = new ConstantUnion[objectSize];
678 for (size_t i = 0; i < objectSize; ++i)
679 {
680 rightUnionArray[i] = *node->getUnionArrayPointer();
681 }
682 returnType = getType();
683 }
684 else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1)
685 {
686 // for a case like float f = vec4(2,3,4,5) + 1.2;
687 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
688 for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
689 {
690 unionArray[i] = *getUnionArrayPointer();
691 }
692 returnType = node->getType();
693 objectSize = constantNode->getType().getObjectSize();
694 }
695
696 ConstantUnion *tempConstArray = NULL;
697 TIntermConstantUnion *tempNode;
698
699 bool boolNodeFlag = false;
700 switch(op)
701 {
702 case EOpAdd:
703 tempConstArray = new ConstantUnion[objectSize];
704 for (size_t i = 0; i < objectSize; i++)
705 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
706 break;
707 case EOpSub:
708 tempConstArray = new ConstantUnion[objectSize];
709 for (size_t i = 0; i < objectSize; i++)
710 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
711 break;
712
713 case EOpMul:
714 case EOpVectorTimesScalar:
715 case EOpMatrixTimesScalar:
716 tempConstArray = new ConstantUnion[objectSize];
717 for (size_t i = 0; i < objectSize; i++)
718 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
719 break;
720
721 case EOpMatrixTimesMatrix:
722 {
723 if (getType().getBasicType() != EbtFloat ||
724 node->getBasicType() != EbtFloat)
725 {
726 infoSink.info.message(
727 EPrefixInternalError, getLine(),
728 "Constant Folding cannot be done for matrix multiply");
Jamie Madillb7757782015-04-14 15:29:29 +0000729 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400730 }
731
732 const int leftCols = getCols();
733 const int leftRows = getRows();
734 const int rightCols = constantNode->getType().getCols();
735 const int rightRows = constantNode->getType().getRows();
736 const int resultCols = rightCols;
737 const int resultRows = leftRows;
738
739 tempConstArray = new ConstantUnion[resultCols*resultRows];
740 for (int row = 0; row < resultRows; row++)
741 {
742 for (int column = 0; column < resultCols; column++)
743 {
744 tempConstArray[resultRows * column + row].setFConst(0.0f);
745 for (int i = 0; i < leftCols; i++)
746 {
747 tempConstArray[resultRows * column + row].setFConst(
748 tempConstArray[resultRows * column + row].getFConst() +
749 unionArray[i * leftRows + row].getFConst() *
750 rightUnionArray[column * rightRows + i].getFConst());
751 }
752 }
753 }
754
755 // update return type for matrix product
Minmin Gong794e0002015-04-07 18:31:54 -0700756 returnType.setPrimarySize(static_cast<unsigned char>(resultCols));
757 returnType.setSecondarySize(static_cast<unsigned char>(resultRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400758 }
759 break;
760
761 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200762 case EOpIMod:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400763 {
764 tempConstArray = new ConstantUnion[objectSize];
765 for (size_t i = 0; i < objectSize; i++)
766 {
767 switch (getType().getBasicType())
768 {
769 case EbtFloat:
770 if (rightUnionArray[i] == 0.0f)
771 {
772 infoSink.info.message(
773 EPrefixWarning, getLine(),
774 "Divide by zero error during constant folding");
775 tempConstArray[i].setFConst(
776 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
777 }
778 else
779 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200780 ASSERT(op == EOpDiv);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400781 tempConstArray[i].setFConst(
782 unionArray[i].getFConst() /
783 rightUnionArray[i].getFConst());
784 }
785 break;
786
787 case EbtInt:
788 if (rightUnionArray[i] == 0)
789 {
790 infoSink.info.message(
791 EPrefixWarning, getLine(),
792 "Divide by zero error during constant folding");
793 tempConstArray[i].setIConst(INT_MAX);
794 }
795 else
796 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200797 if (op == EOpDiv)
798 {
799 tempConstArray[i].setIConst(
800 unionArray[i].getIConst() /
801 rightUnionArray[i].getIConst());
802 }
803 else
804 {
805 ASSERT(op == EOpIMod);
806 tempConstArray[i].setIConst(
807 unionArray[i].getIConst() %
808 rightUnionArray[i].getIConst());
809 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400810 }
811 break;
812
813 case EbtUInt:
814 if (rightUnionArray[i] == 0)
815 {
816 infoSink.info.message(
817 EPrefixWarning, getLine(),
818 "Divide by zero error during constant folding");
819 tempConstArray[i].setUConst(UINT_MAX);
820 }
821 else
822 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200823 if (op == EOpDiv)
824 {
825 tempConstArray[i].setUConst(
826 unionArray[i].getUConst() /
827 rightUnionArray[i].getUConst());
828 }
829 else
830 {
831 ASSERT(op == EOpIMod);
832 tempConstArray[i].setUConst(
833 unionArray[i].getUConst() %
834 rightUnionArray[i].getUConst());
835 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400836 }
837 break;
838
839 default:
840 infoSink.info.message(
841 EPrefixInternalError, getLine(),
842 "Constant folding cannot be done for \"/\"");
Jamie Madillb7757782015-04-14 15:29:29 +0000843 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400844 }
845 }
846 }
847 break;
848
849 case EOpMatrixTimesVector:
850 {
851 if (node->getBasicType() != EbtFloat)
852 {
853 infoSink.info.message(
854 EPrefixInternalError, getLine(),
855 "Constant Folding cannot be done for matrix times vector");
Jamie Madillb7757782015-04-14 15:29:29 +0000856 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400857 }
858
859 const int matrixCols = getCols();
860 const int matrixRows = getRows();
861
862 tempConstArray = new ConstantUnion[matrixRows];
863
864 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
865 {
866 tempConstArray[matrixRow].setFConst(0.0f);
867 for (int col = 0; col < matrixCols; col++)
868 {
869 tempConstArray[matrixRow].setFConst(
870 tempConstArray[matrixRow].getFConst() +
871 unionArray[col * matrixRows + matrixRow].getFConst() *
872 rightUnionArray[col].getFConst());
873 }
874 }
875
876 returnType = node->getType();
Minmin Gong794e0002015-04-07 18:31:54 -0700877 returnType.setPrimarySize(static_cast<unsigned char>(matrixRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400878
879 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
880 tempNode->setLine(getLine());
881
882 return tempNode;
883 }
884
885 case EOpVectorTimesMatrix:
886 {
887 if (getType().getBasicType() != EbtFloat)
888 {
889 infoSink.info.message(
890 EPrefixInternalError, getLine(),
891 "Constant Folding cannot be done for vector times matrix");
Jamie Madillb7757782015-04-14 15:29:29 +0000892 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400893 }
894
895 const int matrixCols = constantNode->getType().getCols();
896 const int matrixRows = constantNode->getType().getRows();
897
898 tempConstArray = new ConstantUnion[matrixCols];
899
900 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
901 {
902 tempConstArray[matrixCol].setFConst(0.0f);
903 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
904 {
905 tempConstArray[matrixCol].setFConst(
906 tempConstArray[matrixCol].getFConst() +
907 unionArray[matrixRow].getFConst() *
908 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
909 }
910 }
911
Minmin Gong794e0002015-04-07 18:31:54 -0700912 returnType.setPrimarySize(static_cast<unsigned char>(matrixCols));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400913 }
914 break;
915
916 case EOpLogicalAnd:
917 // this code is written for possible future use,
918 // will not get executed currently
919 {
920 tempConstArray = new ConstantUnion[objectSize];
921 for (size_t i = 0; i < objectSize; i++)
922 {
923 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
924 }
925 }
926 break;
927
928 case EOpLogicalOr:
929 // this code is written for possible future use,
930 // will not get executed currently
931 {
932 tempConstArray = new ConstantUnion[objectSize];
933 for (size_t i = 0; i < objectSize; i++)
934 {
935 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
936 }
937 }
938 break;
939
940 case EOpLogicalXor:
941 {
942 tempConstArray = new ConstantUnion[objectSize];
943 for (size_t i = 0; i < objectSize; i++)
944 {
945 switch (getType().getBasicType())
946 {
947 case EbtBool:
948 tempConstArray[i].setBConst(
949 unionArray[i] == rightUnionArray[i] ? false : true);
950 break;
951 default:
952 UNREACHABLE();
953 break;
954 }
955 }
956 }
957 break;
958
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200959 case EOpBitwiseAnd:
960 tempConstArray = new ConstantUnion[objectSize];
961 for (size_t i = 0; i < objectSize; i++)
962 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
963 break;
964 case EOpBitwiseXor:
965 tempConstArray = new ConstantUnion[objectSize];
966 for (size_t i = 0; i < objectSize; i++)
967 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
968 break;
969 case EOpBitwiseOr:
970 tempConstArray = new ConstantUnion[objectSize];
971 for (size_t i = 0; i < objectSize; i++)
972 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
973 break;
974 case EOpBitShiftLeft:
975 tempConstArray = new ConstantUnion[objectSize];
976 for (size_t i = 0; i < objectSize; i++)
977 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
978 break;
979 case EOpBitShiftRight:
980 tempConstArray = new ConstantUnion[objectSize];
981 for (size_t i = 0; i < objectSize; i++)
982 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
983 break;
984
Jamie Madillb1a85f42014-08-19 15:23:24 -0400985 case EOpLessThan:
986 ASSERT(objectSize == 1);
987 tempConstArray = new ConstantUnion[1];
988 tempConstArray->setBConst(*unionArray < *rightUnionArray);
989 returnType = TType(EbtBool, EbpUndefined, EvqConst);
990 break;
991
992 case EOpGreaterThan:
993 ASSERT(objectSize == 1);
994 tempConstArray = new ConstantUnion[1];
995 tempConstArray->setBConst(*unionArray > *rightUnionArray);
996 returnType = TType(EbtBool, EbpUndefined, EvqConst);
997 break;
998
999 case EOpLessThanEqual:
1000 {
1001 ASSERT(objectSize == 1);
1002 ConstantUnion constant;
1003 constant.setBConst(*unionArray > *rightUnionArray);
1004 tempConstArray = new ConstantUnion[1];
1005 tempConstArray->setBConst(!constant.getBConst());
1006 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1007 break;
1008 }
1009
1010 case EOpGreaterThanEqual:
1011 {
1012 ASSERT(objectSize == 1);
1013 ConstantUnion constant;
1014 constant.setBConst(*unionArray < *rightUnionArray);
1015 tempConstArray = new ConstantUnion[1];
1016 tempConstArray->setBConst(!constant.getBConst());
1017 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1018 break;
1019 }
1020
1021 case EOpEqual:
1022 if (getType().getBasicType() == EbtStruct)
1023 {
1024 if (!CompareStructure(node->getType(),
1025 node->getUnionArrayPointer(),
1026 unionArray))
1027 {
1028 boolNodeFlag = true;
1029 }
1030 }
1031 else
1032 {
1033 for (size_t i = 0; i < objectSize; i++)
1034 {
1035 if (unionArray[i] != rightUnionArray[i])
1036 {
1037 boolNodeFlag = true;
1038 break; // break out of for loop
1039 }
1040 }
1041 }
1042
1043 tempConstArray = new ConstantUnion[1];
1044 if (!boolNodeFlag)
1045 {
1046 tempConstArray->setBConst(true);
1047 }
1048 else
1049 {
1050 tempConstArray->setBConst(false);
1051 }
1052
1053 tempNode = new TIntermConstantUnion(
1054 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1055 tempNode->setLine(getLine());
1056
1057 return tempNode;
1058
1059 case EOpNotEqual:
1060 if (getType().getBasicType() == EbtStruct)
1061 {
1062 if (CompareStructure(node->getType(),
1063 node->getUnionArrayPointer(),
1064 unionArray))
1065 {
1066 boolNodeFlag = true;
1067 }
1068 }
1069 else
1070 {
1071 for (size_t i = 0; i < objectSize; i++)
1072 {
1073 if (unionArray[i] == rightUnionArray[i])
1074 {
1075 boolNodeFlag = true;
1076 break; // break out of for loop
1077 }
1078 }
1079 }
1080
1081 tempConstArray = new ConstantUnion[1];
1082 if (!boolNodeFlag)
1083 {
1084 tempConstArray->setBConst(true);
1085 }
1086 else
1087 {
1088 tempConstArray->setBConst(false);
1089 }
1090
1091 tempNode = new TIntermConstantUnion(
1092 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1093 tempNode->setLine(getLine());
1094
1095 return tempNode;
1096
1097 default:
1098 infoSink.info.message(
1099 EPrefixInternalError, getLine(),
1100 "Invalid operator for constant folding");
Jamie Madillb7757782015-04-14 15:29:29 +00001101 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001102 }
1103 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1104 tempNode->setLine(getLine());
1105
1106 return tempNode;
1107 }
1108 else
1109 {
1110 //
1111 // Do unary operations
1112 //
1113 TIntermConstantUnion *newNode = 0;
1114 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1115 for (size_t i = 0; i < objectSize; i++)
1116 {
1117 switch(op)
1118 {
1119 case EOpNegative:
1120 switch (getType().getBasicType())
1121 {
1122 case EbtFloat:
1123 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1124 break;
1125 case EbtInt:
1126 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1127 break;
1128 case EbtUInt:
1129 tempConstArray[i].setUConst(static_cast<unsigned int>(
1130 -static_cast<int>(unionArray[i].getUConst())));
1131 break;
1132 default:
1133 infoSink.info.message(
1134 EPrefixInternalError, getLine(),
1135 "Unary operation not folded into constant");
Jamie Madillb7757782015-04-14 15:29:29 +00001136 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001137 }
1138 break;
1139
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001140 case EOpPositive:
1141 switch (getType().getBasicType())
1142 {
1143 case EbtFloat:
1144 tempConstArray[i].setFConst(unionArray[i].getFConst());
1145 break;
1146 case EbtInt:
1147 tempConstArray[i].setIConst(unionArray[i].getIConst());
1148 break;
1149 case EbtUInt:
1150 tempConstArray[i].setUConst(static_cast<unsigned int>(
1151 static_cast<int>(unionArray[i].getUConst())));
1152 break;
1153 default:
1154 infoSink.info.message(
1155 EPrefixInternalError, getLine(),
1156 "Unary operation not folded into constant");
Jamie Madillb7757782015-04-14 15:29:29 +00001157 return NULL;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001158 }
1159 break;
1160
Jamie Madillb1a85f42014-08-19 15:23:24 -04001161 case EOpLogicalNot:
1162 // this code is written for possible future use,
1163 // will not get executed currently
1164 switch (getType().getBasicType())
1165 {
1166 case EbtBool:
1167 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1168 break;
1169 default:
1170 infoSink.info.message(
1171 EPrefixInternalError, getLine(),
1172 "Unary operation not folded into constant");
Jamie Madillb7757782015-04-14 15:29:29 +00001173 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001174 }
1175 break;
1176
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001177 case EOpBitwiseNot:
1178 switch (getType().getBasicType())
1179 {
1180 case EbtInt:
1181 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1182 break;
1183 case EbtUInt:
1184 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1185 break;
1186 default:
1187 infoSink.info.message(
1188 EPrefixInternalError, getLine(),
1189 "Unary operation not folded into constant");
Jamie Madillb7757782015-04-14 15:29:29 +00001190 return NULL;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001191 }
1192 break;
1193
Arun Patole9dea48f2015-04-02 11:45:09 +05301194 case EOpRadians:
1195 if (getType().getBasicType() == EbtFloat)
1196 {
1197 tempConstArray[i].setFConst(kDegreesToRadiansMultiplier * unionArray[i].getFConst());
1198 break;
1199 }
1200 infoSink.info.message(
1201 EPrefixInternalError, getLine(),
1202 "Unary operation not folded into constant");
1203 return nullptr;
1204
1205 case EOpDegrees:
1206 if (getType().getBasicType() == EbtFloat)
1207 {
1208 tempConstArray[i].setFConst(kRadiansToDegreesMultiplier * unionArray[i].getFConst());
1209 break;
1210 }
1211 infoSink.info.message(
1212 EPrefixInternalError, getLine(),
1213 "Unary operation not folded into constant");
1214 return nullptr;
1215
1216 case EOpSin:
1217 if (!foldFloatTypeUnary(unionArray[i], &sinf, infoSink, &tempConstArray[i]))
1218 return nullptr;
1219 break;
1220
1221 case EOpCos:
1222 if (!foldFloatTypeUnary(unionArray[i], &cosf, infoSink, &tempConstArray[i]))
1223 return nullptr;
1224 break;
1225
1226 case EOpTan:
1227 if (!foldFloatTypeUnary(unionArray[i], &tanf, infoSink, &tempConstArray[i]))
1228 return nullptr;
1229 break;
1230
1231 case EOpAsin:
1232 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1233 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1234 tempConstArray[i].setFConst(0.0f);
1235 else if (!foldFloatTypeUnary(unionArray[i], &asinf, infoSink, &tempConstArray[i]))
1236 return nullptr;
1237 break;
1238
1239 case EOpAcos:
1240 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1241 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) > 1.0f)
1242 tempConstArray[i].setFConst(0.0f);
1243 else if (!foldFloatTypeUnary(unionArray[i], &acosf, infoSink, &tempConstArray[i]))
1244 return nullptr;
1245 break;
1246
1247 case EOpAtan:
1248 if (!foldFloatTypeUnary(unionArray[i], &atanf, infoSink, &tempConstArray[i]))
1249 return nullptr;
1250 break;
1251
1252 case EOpSinh:
1253 if (!foldFloatTypeUnary(unionArray[i], &sinhf, infoSink, &tempConstArray[i]))
1254 return nullptr;
1255 break;
1256
1257 case EOpCosh:
1258 if (!foldFloatTypeUnary(unionArray[i], &coshf, infoSink, &tempConstArray[i]))
1259 return nullptr;
1260 break;
1261
1262 case EOpTanh:
1263 if (!foldFloatTypeUnary(unionArray[i], &tanhf, infoSink, &tempConstArray[i]))
1264 return nullptr;
1265 break;
1266
1267 case EOpAsinh:
1268 if (!foldFloatTypeUnary(unionArray[i], &asinhf, infoSink, &tempConstArray[i]))
1269 return nullptr;
1270 break;
1271
1272 case EOpAcosh:
1273 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1274 if (getType().getBasicType() == EbtFloat && unionArray[i].getFConst() < 1.0f)
1275 tempConstArray[i].setFConst(0.0f);
1276 else if (!foldFloatTypeUnary(unionArray[i], &acoshf, infoSink, &tempConstArray[i]))
1277 return nullptr;
1278 break;
1279
1280 case EOpAtanh:
1281 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1282 if (getType().getBasicType() == EbtFloat && fabsf(unionArray[i].getFConst()) >= 1.0f)
1283 tempConstArray[i].setFConst(0.0f);
1284 else if (!foldFloatTypeUnary(unionArray[i], &atanhf, infoSink, &tempConstArray[i]))
1285 return nullptr;
1286 break;
1287
Arun Patole97dc22e2015-04-06 17:35:38 +05301288 case EOpAbs:
1289 switch (getType().getBasicType())
1290 {
1291 case EbtFloat:
1292 tempConstArray[i].setFConst(fabsf(unionArray[i].getFConst()));
1293 break;
1294 case EbtInt:
1295 tempConstArray[i].setIConst(abs(unionArray[i].getIConst()));
1296 break;
1297 default:
1298 infoSink.info.message(
1299 EPrefixInternalError, getLine(),
1300 "Unary operation not folded into constant");
1301 return nullptr;
1302 }
1303 break;
1304
1305 case EOpSign:
1306 switch (getType().getBasicType())
1307 {
1308 case EbtFloat:
1309 {
1310 float fConst = unionArray[i].getFConst();
1311 float fResult = 0.0f;
1312 if (fConst > 0.0f)
1313 fResult = 1.0f;
1314 else if (fConst < 0.0f)
1315 fResult = -1.0f;
1316 tempConstArray[i].setFConst(fResult);
1317 }
1318 break;
1319 case EbtInt:
1320 {
1321 int iConst = unionArray[i].getIConst();
1322 int iResult = 0;
1323 if (iConst > 0)
1324 iResult = 1;
1325 else if (iConst < 0)
1326 iResult = -1;
1327 tempConstArray[i].setIConst(iResult);
1328 }
1329 break;
1330 default:
1331 infoSink.info.message(
1332 EPrefixInternalError, getLine(),
1333 "Unary operation not folded into constant");
1334 return nullptr;
1335 }
1336 break;
1337
1338 case EOpFloor:
1339 if (!foldFloatTypeUnary(unionArray[i], &floorf, infoSink, &tempConstArray[i]))
1340 return nullptr;
1341 break;
1342
1343 case EOpTrunc:
1344 if (!foldFloatTypeUnary(unionArray[i], &truncf, infoSink, &tempConstArray[i]))
1345 return nullptr;
1346 break;
1347
1348 case EOpRound:
1349 if (!foldFloatTypeUnary(unionArray[i], &roundf, infoSink, &tempConstArray[i]))
1350 return nullptr;
1351 break;
1352
1353 case EOpRoundEven:
1354 if (getType().getBasicType() == EbtFloat)
1355 {
1356 float x = unionArray[i].getFConst();
1357 float result;
1358 float fractPart = modff(x, &result);
1359 if (fabsf(fractPart) == 0.5f)
1360 result = 2.0f * roundf(x / 2.0f);
1361 else
1362 result = roundf(x);
1363 tempConstArray[i].setFConst(result);
1364 break;
1365 }
1366 infoSink.info.message(
1367 EPrefixInternalError, getLine(),
1368 "Unary operation not folded into constant");
1369 return nullptr;
1370
1371 case EOpCeil:
1372 if (!foldFloatTypeUnary(unionArray[i], &ceilf, infoSink, &tempConstArray[i]))
1373 return nullptr;
1374 break;
1375
1376 case EOpFract:
1377 if (getType().getBasicType() == EbtFloat)
1378 {
1379 float x = unionArray[i].getFConst();
1380 tempConstArray[i].setFConst(x - floorf(x));
1381 break;
1382 }
1383 infoSink.info.message(
1384 EPrefixInternalError, getLine(),
1385 "Unary operation not folded into constant");
1386 return nullptr;
1387
Jamie Madillb1a85f42014-08-19 15:23:24 -04001388 default:
Jamie Madillb7757782015-04-14 15:29:29 +00001389 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001390 }
1391 }
1392 newNode = new TIntermConstantUnion(tempConstArray, getType());
1393 newNode->setLine(getLine());
1394 return newNode;
1395 }
1396}
1397
Arun Patole9dea48f2015-04-02 11:45:09 +05301398bool TIntermConstantUnion::foldFloatTypeUnary(const ConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1399 TInfoSink &infoSink, ConstantUnion *result) const
1400{
1401 ASSERT(builtinFunc);
1402
1403 if (getType().getBasicType() == EbtFloat)
1404 {
1405 result->setFConst(builtinFunc(parameter.getFConst()));
1406 return true;
1407 }
1408
1409 infoSink.info.message(
1410 EPrefixInternalError, getLine(),
1411 "Unary operation not folded into constant");
1412 return false;
1413}
1414
Jamie Madillb1a85f42014-08-19 15:23:24 -04001415// static
1416TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1417{
1418 if (hashFunction == NULL || name.empty())
1419 return name;
1420 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1421 TStringStream stream;
1422 stream << HASHED_NAME_PREFIX << std::hex << number;
1423 TString hashedName = stream.str();
1424 return hashedName;
1425}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001426
1427void TIntermTraverser::updateTree()
1428{
1429 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
1430 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001431 const NodeUpdateEntry &replacement = mReplacements[ii];
1432 ASSERT(replacement.parent);
1433 bool replaced = replacement.parent->replaceChildNode(
1434 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001435 ASSERT(replaced);
1436
Olli Etuahocd94ef92015-04-16 19:18:10 +03001437 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001438 {
1439 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03001440 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001441 // be replaced, we need to make sure we don't update the replaced
1442 // node; instead, we update the replacement node.
1443 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
1444 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001445 NodeUpdateEntry &replacement2 = mReplacements[jj];
1446 if (replacement2.parent == replacement.original)
1447 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001448 }
1449 }
1450 }
1451}