blob: 5b55e1515f26b0c048e4c67d0f8d93d14fbac426 [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>
13#include <algorithm>
14
15#include "compiler/translator/HashNames.h"
16#include "compiler/translator/IntermNode.h"
17#include "compiler/translator/SymbolTable.h"
18
19namespace
20{
21
22TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
23{
24 return left > right ? left : right;
25}
26
27bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
28{
29 switch (op)
30 {
31 case EOpMul:
32 case EOpMulAssign:
33 return left.getNominalSize() == right.getNominalSize() &&
34 left.getSecondarySize() == right.getSecondarySize();
35 case EOpVectorTimesScalar:
36 case EOpVectorTimesScalarAssign:
37 return true;
38 case EOpVectorTimesMatrix:
39 return left.getNominalSize() == right.getRows();
40 case EOpVectorTimesMatrixAssign:
41 return left.getNominalSize() == right.getRows() &&
42 left.getNominalSize() == right.getCols();
43 case EOpMatrixTimesVector:
44 return left.getCols() == right.getNominalSize();
45 case EOpMatrixTimesScalar:
46 case EOpMatrixTimesScalarAssign:
47 return true;
48 case EOpMatrixTimesMatrix:
49 return left.getCols() == right.getRows();
50 case EOpMatrixTimesMatrixAssign:
51 return left.getCols() == right.getCols() &&
52 left.getRows() == right.getRows();
53
54 default:
55 UNREACHABLE();
56 return false;
57 }
58}
59
60bool CompareStructure(const TType& leftNodeType,
61 ConstantUnion *rightUnionArray,
62 ConstantUnion *leftUnionArray);
63
64bool CompareStruct(const TType &leftNodeType,
65 ConstantUnion *rightUnionArray,
66 ConstantUnion *leftUnionArray)
67{
68 const TFieldList &fields = leftNodeType.getStruct()->fields();
69
70 size_t structSize = fields.size();
71 size_t index = 0;
72
73 for (size_t j = 0; j < structSize; j++)
74 {
75 size_t size = fields[j]->type()->getObjectSize();
76 for (size_t i = 0; i < size; i++)
77 {
78 if (fields[j]->type()->getBasicType() == EbtStruct)
79 {
80 if (!CompareStructure(*fields[j]->type(),
81 &rightUnionArray[index],
82 &leftUnionArray[index]))
83 {
84 return false;
85 }
86 }
87 else
88 {
89 if (leftUnionArray[index] != rightUnionArray[index])
90 return false;
91 index++;
92 }
93 }
94 }
95 return true;
96}
97
98bool CompareStructure(const TType &leftNodeType,
99 ConstantUnion *rightUnionArray,
100 ConstantUnion *leftUnionArray)
101{
102 if (leftNodeType.isArray())
103 {
104 TType typeWithoutArrayness = leftNodeType;
105 typeWithoutArrayness.clearArrayness();
106
107 size_t arraySize = leftNodeType.getArraySize();
108
109 for (size_t i = 0; i < arraySize; ++i)
110 {
111 size_t offset = typeWithoutArrayness.getObjectSize() * i;
112 if (!CompareStruct(typeWithoutArrayness,
113 &rightUnionArray[offset],
114 &leftUnionArray[offset]))
115 {
116 return false;
117 }
118 }
119 }
120 else
121 {
122 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
123 }
124 return true;
125}
126
127} // namespace anonymous
128
129
130////////////////////////////////////////////////////////////////
131//
132// Member functions of the nodes used for building the tree.
133//
134////////////////////////////////////////////////////////////////
135
Olli Etuahod2a67b92014-10-21 16:42:57 +0300136void TIntermTyped::setTypePreservePrecision(const TType &t)
137{
138 TPrecision precision = getPrecision();
139 mType = t;
140 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
141 mType.setPrecision(precision);
142}
143
Jamie Madillb1a85f42014-08-19 15:23:24 -0400144#define REPLACE_IF_IS(node, type, original, replacement) \
145 if (node == original) { \
146 node = static_cast<type *>(replacement); \
147 return true; \
148 }
149
150bool TIntermLoop::replaceChildNode(
151 TIntermNode *original, TIntermNode *replacement)
152{
153 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
154 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
155 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
156 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
157 return false;
158}
159
Jamie Madillb1a85f42014-08-19 15:23:24 -0400160bool TIntermBranch::replaceChildNode(
161 TIntermNode *original, TIntermNode *replacement)
162{
163 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
164 return false;
165}
166
Jamie Madillb1a85f42014-08-19 15:23:24 -0400167bool TIntermBinary::replaceChildNode(
168 TIntermNode *original, TIntermNode *replacement)
169{
170 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
171 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
172 return false;
173}
174
Jamie Madillb1a85f42014-08-19 15:23:24 -0400175bool TIntermUnary::replaceChildNode(
176 TIntermNode *original, TIntermNode *replacement)
177{
178 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
179 return false;
180}
181
Jamie Madillb1a85f42014-08-19 15:23:24 -0400182bool TIntermAggregate::replaceChildNode(
183 TIntermNode *original, TIntermNode *replacement)
184{
185 for (size_t ii = 0; ii < mSequence.size(); ++ii)
186 {
187 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
188 }
189 return false;
190}
191
Olli Etuahod2a67b92014-10-21 16:42:57 +0300192void TIntermAggregate::setPrecisionFromChildren()
193{
194 if (getBasicType() == EbtBool)
195 {
196 mType.setPrecision(EbpUndefined);
197 return;
198 }
199
200 TPrecision precision = EbpUndefined;
201 TIntermSequence::iterator childIter = mSequence.begin();
202 while (childIter != mSequence.end())
203 {
204 TIntermTyped *typed = (*childIter)->getAsTyped();
205 if (typed)
206 precision = GetHigherPrecision(typed->getPrecision(), precision);
207 ++childIter;
208 }
209 mType.setPrecision(precision);
210}
211
212void TIntermAggregate::setBuiltInFunctionPrecision()
213{
214 // All built-ins returning bool should be handled as ops, not functions.
215 ASSERT(getBasicType() != EbtBool);
216
217 TPrecision precision = EbpUndefined;
218 TIntermSequence::iterator childIter = mSequence.begin();
219 while (childIter != mSequence.end())
220 {
221 TIntermTyped *typed = (*childIter)->getAsTyped();
222 // ESSL spec section 8: texture functions get their precision from the sampler.
223 if (typed && IsSampler(typed->getBasicType()))
224 {
225 precision = typed->getPrecision();
226 break;
227 }
228 ++childIter;
229 }
230 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
231 // All other functions that take a sampler are assumed to be texture functions.
232 if (mName.find("textureSize") == 0)
233 mType.setPrecision(EbpHigh);
234 else
235 mType.setPrecision(precision);
236}
237
Jamie Madillb1a85f42014-08-19 15:23:24 -0400238bool TIntermSelection::replaceChildNode(
239 TIntermNode *original, TIntermNode *replacement)
240{
241 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
242 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
243 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
244 return false;
245}
246
Olli Etuahoa3a36662015-02-17 13:46:51 +0200247bool TIntermSwitch::replaceChildNode(
248 TIntermNode *original, TIntermNode *replacement)
249{
250 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
251 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
252 return false;
253}
254
255bool TIntermCase::replaceChildNode(
256 TIntermNode *original, TIntermNode *replacement)
257{
258 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
259 return false;
260}
261
Jamie Madillb1a85f42014-08-19 15:23:24 -0400262//
263// Say whether or not an operation node changes the value of a variable.
264//
265bool TIntermOperator::isAssignment() const
266{
267 switch (mOp)
268 {
269 case EOpPostIncrement:
270 case EOpPostDecrement:
271 case EOpPreIncrement:
272 case EOpPreDecrement:
273 case EOpAssign:
274 case EOpAddAssign:
275 case EOpSubAssign:
276 case EOpMulAssign:
277 case EOpVectorTimesMatrixAssign:
278 case EOpVectorTimesScalarAssign:
279 case EOpMatrixTimesScalarAssign:
280 case EOpMatrixTimesMatrixAssign:
281 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200282 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200283 case EOpBitShiftLeftAssign:
284 case EOpBitShiftRightAssign:
285 case EOpBitwiseAndAssign:
286 case EOpBitwiseXorAssign:
287 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400288 return true;
289 default:
290 return false;
291 }
292}
293
294//
295// returns true if the operator is for one of the constructors
296//
297bool TIntermOperator::isConstructor() const
298{
299 switch (mOp)
300 {
301 case EOpConstructVec2:
302 case EOpConstructVec3:
303 case EOpConstructVec4:
304 case EOpConstructMat2:
305 case EOpConstructMat3:
306 case EOpConstructMat4:
307 case EOpConstructFloat:
308 case EOpConstructIVec2:
309 case EOpConstructIVec3:
310 case EOpConstructIVec4:
311 case EOpConstructInt:
312 case EOpConstructUVec2:
313 case EOpConstructUVec3:
314 case EOpConstructUVec4:
315 case EOpConstructUInt:
316 case EOpConstructBVec2:
317 case EOpConstructBVec3:
318 case EOpConstructBVec4:
319 case EOpConstructBool:
320 case EOpConstructStruct:
321 return true;
322 default:
323 return false;
324 }
325}
326
327//
328// Make sure the type of a unary operator is appropriate for its
329// combination of operation and operand type.
330//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200331void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400332{
333 switch (mOp)
334 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200335 case EOpFloatBitsToInt:
336 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200337 case EOpIntBitsToFloat:
338 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200339 case EOpPackSnorm2x16:
340 case EOpPackUnorm2x16:
341 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200342 case EOpUnpackSnorm2x16:
343 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200344 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530345 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200346 case EOpUnpackHalf2x16:
347 mType.setPrecision(EbpMedium);
348 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400349 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200350 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400351 }
352
Olli Etuahof6c694b2015-03-26 14:50:53 +0200353 if (funcReturnType != nullptr)
354 {
355 if (funcReturnType->getBasicType() == EbtBool)
356 {
357 // Bool types should not have precision.
358 setType(*funcReturnType);
359 }
360 else
361 {
362 // Precision of the node has been set based on the operand.
363 setTypePreservePrecision(*funcReturnType);
364 }
365 }
366
Jamie Madillb1a85f42014-08-19 15:23:24 -0400367 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400368}
369
370//
371// Establishes the type of the resultant operation, as well as
372// makes the operator the correct one for the operands.
373//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200374// For lots of operations it should already be established that the operand
375// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400376//
377bool TIntermBinary::promote(TInfoSink &infoSink)
378{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200379 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400380
Jamie Madillb1a85f42014-08-19 15:23:24 -0400381 //
382 // Base assumption: just make the type the same as the left
383 // operand. Then only deviations from this need be coded.
384 //
385 setType(mLeft->getType());
386
387 // The result gets promoted to the highest precision.
388 TPrecision higherPrecision = GetHigherPrecision(
389 mLeft->getPrecision(), mRight->getPrecision());
390 getTypePointer()->setPrecision(higherPrecision);
391
392 // Binary operations results in temporary variables unless both
393 // operands are const.
394 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
395 {
396 getTypePointer()->setQualifier(EvqTemporary);
397 }
398
399 const int nominalSize =
400 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
401
402 //
403 // All scalars or structs. Code after this test assumes this case is removed!
404 //
405 if (nominalSize == 1)
406 {
407 switch (mOp)
408 {
409 //
410 // Promote to conditional
411 //
412 case EOpEqual:
413 case EOpNotEqual:
414 case EOpLessThan:
415 case EOpGreaterThan:
416 case EOpLessThanEqual:
417 case EOpGreaterThanEqual:
418 setType(TType(EbtBool, EbpUndefined));
419 break;
420
421 //
422 // And and Or operate on conditionals
423 //
424 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200425 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400426 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200427 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400428 setType(TType(EbtBool, EbpUndefined));
429 break;
430
431 default:
432 break;
433 }
434 return true;
435 }
436
437 // If we reach here, at least one of the operands is vector or matrix.
438 // The other operand could be a scalar, vector, or matrix.
439 // Can these two operands be combined?
440 //
441 TBasicType basicType = mLeft->getBasicType();
442 switch (mOp)
443 {
444 case EOpMul:
445 if (!mLeft->isMatrix() && mRight->isMatrix())
446 {
447 if (mLeft->isVector())
448 {
449 mOp = EOpVectorTimesMatrix;
450 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700451 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400452 }
453 else
454 {
455 mOp = EOpMatrixTimesScalar;
456 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700457 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400458 }
459 }
460 else if (mLeft->isMatrix() && !mRight->isMatrix())
461 {
462 if (mRight->isVector())
463 {
464 mOp = EOpMatrixTimesVector;
465 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700466 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400467 }
468 else
469 {
470 mOp = EOpMatrixTimesScalar;
471 }
472 }
473 else if (mLeft->isMatrix() && mRight->isMatrix())
474 {
475 mOp = EOpMatrixTimesMatrix;
476 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700477 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400478 }
479 else if (!mLeft->isMatrix() && !mRight->isMatrix())
480 {
481 if (mLeft->isVector() && mRight->isVector())
482 {
483 // leave as component product
484 }
485 else if (mLeft->isVector() || mRight->isVector())
486 {
487 mOp = EOpVectorTimesScalar;
488 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700489 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400490 }
491 }
492 else
493 {
494 infoSink.info.message(EPrefixInternalError, getLine(),
495 "Missing elses");
496 return false;
497 }
498
499 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
500 {
501 return false;
502 }
503 break;
504
505 case EOpMulAssign:
506 if (!mLeft->isMatrix() && mRight->isMatrix())
507 {
508 if (mLeft->isVector())
509 {
510 mOp = EOpVectorTimesMatrixAssign;
511 }
512 else
513 {
514 return false;
515 }
516 }
517 else if (mLeft->isMatrix() && !mRight->isMatrix())
518 {
519 if (mRight->isVector())
520 {
521 return false;
522 }
523 else
524 {
525 mOp = EOpMatrixTimesScalarAssign;
526 }
527 }
528 else if (mLeft->isMatrix() && mRight->isMatrix())
529 {
530 mOp = EOpMatrixTimesMatrixAssign;
531 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700532 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400533 }
534 else if (!mLeft->isMatrix() && !mRight->isMatrix())
535 {
536 if (mLeft->isVector() && mRight->isVector())
537 {
538 // leave as component product
539 }
540 else if (mLeft->isVector() || mRight->isVector())
541 {
542 if (!mLeft->isVector())
543 return false;
544 mOp = EOpVectorTimesScalarAssign;
545 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700546 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400547 }
548 }
549 else
550 {
551 infoSink.info.message(EPrefixInternalError, getLine(),
552 "Missing elses");
553 return false;
554 }
555
556 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
557 {
558 return false;
559 }
560 break;
561
562 case EOpAssign:
563 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200564 // No more additional checks are needed.
565 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
566 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
567 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400568 case EOpAdd:
569 case EOpSub:
570 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200571 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200572 case EOpBitShiftLeft:
573 case EOpBitShiftRight:
574 case EOpBitwiseAnd:
575 case EOpBitwiseXor:
576 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400577 case EOpAddAssign:
578 case EOpSubAssign:
579 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200580 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200581 case EOpBitShiftLeftAssign:
582 case EOpBitShiftRightAssign:
583 case EOpBitwiseAndAssign:
584 case EOpBitwiseXorAssign:
585 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400586 if ((mLeft->isMatrix() && mRight->isVector()) ||
587 (mLeft->isVector() && mRight->isMatrix()))
588 {
589 return false;
590 }
591
592 // Are the sizes compatible?
593 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
594 mLeft->getSecondarySize() != mRight->getSecondarySize())
595 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200596 // If the nominal sizes of operands do not match:
597 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400598 if (!mLeft->isScalar() && !mRight->isScalar())
599 return false;
600
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200601 // In the case of compound assignment other than multiply-assign,
602 // the right side needs to be a scalar. Otherwise a vector/matrix
603 // would be assigned to a scalar. A scalar can't be shifted by a
604 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200605 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200606 (isAssignment() ||
607 mOp == EOpBitShiftLeft ||
608 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200609 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400610 }
611
612 {
613 const int secondarySize = std::max(
614 mLeft->getSecondarySize(), mRight->getSecondarySize());
615 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700616 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200617 if (mLeft->isArray())
618 {
619 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
620 mType.setArraySize(mLeft->getArraySize());
621 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400622 }
623 break;
624
625 case EOpEqual:
626 case EOpNotEqual:
627 case EOpLessThan:
628 case EOpGreaterThan:
629 case EOpLessThanEqual:
630 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200631 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
632 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400633 setType(TType(EbtBool, EbpUndefined));
634 break;
635
636 default:
637 return false;
638 }
639 return true;
640}
641
642//
643// The fold functions see if an operation on a constant can be done in place,
644// without generating run-time code.
645//
646// Returns the node to keep using, which may or may not be the node passed in.
647//
648TIntermTyped *TIntermConstantUnion::fold(
649 TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink)
650{
651 ConstantUnion *unionArray = getUnionArrayPointer();
652
653 if (!unionArray)
Jamie Madillb7757782015-04-14 15:29:29 +0000654 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400655
656 size_t objectSize = getType().getObjectSize();
657
658 if (constantNode)
659 {
660 // binary operations
661 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
662 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
663 TType returnType = getType();
664
665 if (!rightUnionArray)
Jamie Madillb7757782015-04-14 15:29:29 +0000666 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400667
668 // for a case like float f = 1.2 + vec4(2,3,4,5);
669 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1)
670 {
671 rightUnionArray = new ConstantUnion[objectSize];
672 for (size_t i = 0; i < objectSize; ++i)
673 {
674 rightUnionArray[i] = *node->getUnionArrayPointer();
675 }
676 returnType = getType();
677 }
678 else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1)
679 {
680 // for a case like float f = vec4(2,3,4,5) + 1.2;
681 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
682 for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
683 {
684 unionArray[i] = *getUnionArrayPointer();
685 }
686 returnType = node->getType();
687 objectSize = constantNode->getType().getObjectSize();
688 }
689
690 ConstantUnion *tempConstArray = NULL;
691 TIntermConstantUnion *tempNode;
692
693 bool boolNodeFlag = false;
694 switch(op)
695 {
696 case EOpAdd:
697 tempConstArray = new ConstantUnion[objectSize];
698 for (size_t i = 0; i < objectSize; i++)
699 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
700 break;
701 case EOpSub:
702 tempConstArray = new ConstantUnion[objectSize];
703 for (size_t i = 0; i < objectSize; i++)
704 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
705 break;
706
707 case EOpMul:
708 case EOpVectorTimesScalar:
709 case EOpMatrixTimesScalar:
710 tempConstArray = new ConstantUnion[objectSize];
711 for (size_t i = 0; i < objectSize; i++)
712 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
713 break;
714
715 case EOpMatrixTimesMatrix:
716 {
717 if (getType().getBasicType() != EbtFloat ||
718 node->getBasicType() != EbtFloat)
719 {
720 infoSink.info.message(
721 EPrefixInternalError, getLine(),
722 "Constant Folding cannot be done for matrix multiply");
Jamie Madillb7757782015-04-14 15:29:29 +0000723 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400724 }
725
726 const int leftCols = getCols();
727 const int leftRows = getRows();
728 const int rightCols = constantNode->getType().getCols();
729 const int rightRows = constantNode->getType().getRows();
730 const int resultCols = rightCols;
731 const int resultRows = leftRows;
732
733 tempConstArray = new ConstantUnion[resultCols*resultRows];
734 for (int row = 0; row < resultRows; row++)
735 {
736 for (int column = 0; column < resultCols; column++)
737 {
738 tempConstArray[resultRows * column + row].setFConst(0.0f);
739 for (int i = 0; i < leftCols; i++)
740 {
741 tempConstArray[resultRows * column + row].setFConst(
742 tempConstArray[resultRows * column + row].getFConst() +
743 unionArray[i * leftRows + row].getFConst() *
744 rightUnionArray[column * rightRows + i].getFConst());
745 }
746 }
747 }
748
749 // update return type for matrix product
Minmin Gong794e0002015-04-07 18:31:54 -0700750 returnType.setPrimarySize(static_cast<unsigned char>(resultCols));
751 returnType.setSecondarySize(static_cast<unsigned char>(resultRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400752 }
753 break;
754
755 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200756 case EOpIMod:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400757 {
758 tempConstArray = new ConstantUnion[objectSize];
759 for (size_t i = 0; i < objectSize; i++)
760 {
761 switch (getType().getBasicType())
762 {
763 case EbtFloat:
764 if (rightUnionArray[i] == 0.0f)
765 {
766 infoSink.info.message(
767 EPrefixWarning, getLine(),
768 "Divide by zero error during constant folding");
769 tempConstArray[i].setFConst(
770 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
771 }
772 else
773 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200774 ASSERT(op == EOpDiv);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400775 tempConstArray[i].setFConst(
776 unionArray[i].getFConst() /
777 rightUnionArray[i].getFConst());
778 }
779 break;
780
781 case EbtInt:
782 if (rightUnionArray[i] == 0)
783 {
784 infoSink.info.message(
785 EPrefixWarning, getLine(),
786 "Divide by zero error during constant folding");
787 tempConstArray[i].setIConst(INT_MAX);
788 }
789 else
790 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200791 if (op == EOpDiv)
792 {
793 tempConstArray[i].setIConst(
794 unionArray[i].getIConst() /
795 rightUnionArray[i].getIConst());
796 }
797 else
798 {
799 ASSERT(op == EOpIMod);
800 tempConstArray[i].setIConst(
801 unionArray[i].getIConst() %
802 rightUnionArray[i].getIConst());
803 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400804 }
805 break;
806
807 case EbtUInt:
808 if (rightUnionArray[i] == 0)
809 {
810 infoSink.info.message(
811 EPrefixWarning, getLine(),
812 "Divide by zero error during constant folding");
813 tempConstArray[i].setUConst(UINT_MAX);
814 }
815 else
816 {
Olli Etuaho3eab00a2015-02-12 16:02:39 +0200817 if (op == EOpDiv)
818 {
819 tempConstArray[i].setUConst(
820 unionArray[i].getUConst() /
821 rightUnionArray[i].getUConst());
822 }
823 else
824 {
825 ASSERT(op == EOpIMod);
826 tempConstArray[i].setUConst(
827 unionArray[i].getUConst() %
828 rightUnionArray[i].getUConst());
829 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400830 }
831 break;
832
833 default:
834 infoSink.info.message(
835 EPrefixInternalError, getLine(),
836 "Constant folding cannot be done for \"/\"");
Jamie Madillb7757782015-04-14 15:29:29 +0000837 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400838 }
839 }
840 }
841 break;
842
843 case EOpMatrixTimesVector:
844 {
845 if (node->getBasicType() != EbtFloat)
846 {
847 infoSink.info.message(
848 EPrefixInternalError, getLine(),
849 "Constant Folding cannot be done for matrix times vector");
Jamie Madillb7757782015-04-14 15:29:29 +0000850 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400851 }
852
853 const int matrixCols = getCols();
854 const int matrixRows = getRows();
855
856 tempConstArray = new ConstantUnion[matrixRows];
857
858 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
859 {
860 tempConstArray[matrixRow].setFConst(0.0f);
861 for (int col = 0; col < matrixCols; col++)
862 {
863 tempConstArray[matrixRow].setFConst(
864 tempConstArray[matrixRow].getFConst() +
865 unionArray[col * matrixRows + matrixRow].getFConst() *
866 rightUnionArray[col].getFConst());
867 }
868 }
869
870 returnType = node->getType();
Minmin Gong794e0002015-04-07 18:31:54 -0700871 returnType.setPrimarySize(static_cast<unsigned char>(matrixRows));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400872
873 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
874 tempNode->setLine(getLine());
875
876 return tempNode;
877 }
878
879 case EOpVectorTimesMatrix:
880 {
881 if (getType().getBasicType() != EbtFloat)
882 {
883 infoSink.info.message(
884 EPrefixInternalError, getLine(),
885 "Constant Folding cannot be done for vector times matrix");
Jamie Madillb7757782015-04-14 15:29:29 +0000886 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400887 }
888
889 const int matrixCols = constantNode->getType().getCols();
890 const int matrixRows = constantNode->getType().getRows();
891
892 tempConstArray = new ConstantUnion[matrixCols];
893
894 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
895 {
896 tempConstArray[matrixCol].setFConst(0.0f);
897 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
898 {
899 tempConstArray[matrixCol].setFConst(
900 tempConstArray[matrixCol].getFConst() +
901 unionArray[matrixRow].getFConst() *
902 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
903 }
904 }
905
Minmin Gong794e0002015-04-07 18:31:54 -0700906 returnType.setPrimarySize(static_cast<unsigned char>(matrixCols));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400907 }
908 break;
909
910 case EOpLogicalAnd:
911 // this code is written for possible future use,
912 // will not get executed currently
913 {
914 tempConstArray = new ConstantUnion[objectSize];
915 for (size_t i = 0; i < objectSize; i++)
916 {
917 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
918 }
919 }
920 break;
921
922 case EOpLogicalOr:
923 // this code is written for possible future use,
924 // will not get executed currently
925 {
926 tempConstArray = new ConstantUnion[objectSize];
927 for (size_t i = 0; i < objectSize; i++)
928 {
929 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
930 }
931 }
932 break;
933
934 case EOpLogicalXor:
935 {
936 tempConstArray = new ConstantUnion[objectSize];
937 for (size_t i = 0; i < objectSize; i++)
938 {
939 switch (getType().getBasicType())
940 {
941 case EbtBool:
942 tempConstArray[i].setBConst(
943 unionArray[i] == rightUnionArray[i] ? false : true);
944 break;
945 default:
946 UNREACHABLE();
947 break;
948 }
949 }
950 }
951 break;
952
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200953 case EOpBitwiseAnd:
954 tempConstArray = new ConstantUnion[objectSize];
955 for (size_t i = 0; i < objectSize; i++)
956 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
957 break;
958 case EOpBitwiseXor:
959 tempConstArray = new ConstantUnion[objectSize];
960 for (size_t i = 0; i < objectSize; i++)
961 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
962 break;
963 case EOpBitwiseOr:
964 tempConstArray = new ConstantUnion[objectSize];
965 for (size_t i = 0; i < objectSize; i++)
966 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
967 break;
968 case EOpBitShiftLeft:
969 tempConstArray = new ConstantUnion[objectSize];
970 for (size_t i = 0; i < objectSize; i++)
971 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
972 break;
973 case EOpBitShiftRight:
974 tempConstArray = new ConstantUnion[objectSize];
975 for (size_t i = 0; i < objectSize; i++)
976 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
977 break;
978
Jamie Madillb1a85f42014-08-19 15:23:24 -0400979 case EOpLessThan:
980 ASSERT(objectSize == 1);
981 tempConstArray = new ConstantUnion[1];
982 tempConstArray->setBConst(*unionArray < *rightUnionArray);
983 returnType = TType(EbtBool, EbpUndefined, EvqConst);
984 break;
985
986 case EOpGreaterThan:
987 ASSERT(objectSize == 1);
988 tempConstArray = new ConstantUnion[1];
989 tempConstArray->setBConst(*unionArray > *rightUnionArray);
990 returnType = TType(EbtBool, EbpUndefined, EvqConst);
991 break;
992
993 case EOpLessThanEqual:
994 {
995 ASSERT(objectSize == 1);
996 ConstantUnion constant;
997 constant.setBConst(*unionArray > *rightUnionArray);
998 tempConstArray = new ConstantUnion[1];
999 tempConstArray->setBConst(!constant.getBConst());
1000 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1001 break;
1002 }
1003
1004 case EOpGreaterThanEqual:
1005 {
1006 ASSERT(objectSize == 1);
1007 ConstantUnion constant;
1008 constant.setBConst(*unionArray < *rightUnionArray);
1009 tempConstArray = new ConstantUnion[1];
1010 tempConstArray->setBConst(!constant.getBConst());
1011 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1012 break;
1013 }
1014
1015 case EOpEqual:
1016 if (getType().getBasicType() == EbtStruct)
1017 {
1018 if (!CompareStructure(node->getType(),
1019 node->getUnionArrayPointer(),
1020 unionArray))
1021 {
1022 boolNodeFlag = true;
1023 }
1024 }
1025 else
1026 {
1027 for (size_t i = 0; i < objectSize; i++)
1028 {
1029 if (unionArray[i] != rightUnionArray[i])
1030 {
1031 boolNodeFlag = true;
1032 break; // break out of for loop
1033 }
1034 }
1035 }
1036
1037 tempConstArray = new ConstantUnion[1];
1038 if (!boolNodeFlag)
1039 {
1040 tempConstArray->setBConst(true);
1041 }
1042 else
1043 {
1044 tempConstArray->setBConst(false);
1045 }
1046
1047 tempNode = new TIntermConstantUnion(
1048 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1049 tempNode->setLine(getLine());
1050
1051 return tempNode;
1052
1053 case EOpNotEqual:
1054 if (getType().getBasicType() == EbtStruct)
1055 {
1056 if (CompareStructure(node->getType(),
1057 node->getUnionArrayPointer(),
1058 unionArray))
1059 {
1060 boolNodeFlag = true;
1061 }
1062 }
1063 else
1064 {
1065 for (size_t i = 0; i < objectSize; i++)
1066 {
1067 if (unionArray[i] == rightUnionArray[i])
1068 {
1069 boolNodeFlag = true;
1070 break; // break out of for loop
1071 }
1072 }
1073 }
1074
1075 tempConstArray = new ConstantUnion[1];
1076 if (!boolNodeFlag)
1077 {
1078 tempConstArray->setBConst(true);
1079 }
1080 else
1081 {
1082 tempConstArray->setBConst(false);
1083 }
1084
1085 tempNode = new TIntermConstantUnion(
1086 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1087 tempNode->setLine(getLine());
1088
1089 return tempNode;
1090
1091 default:
1092 infoSink.info.message(
1093 EPrefixInternalError, getLine(),
1094 "Invalid operator for constant folding");
Jamie Madillb7757782015-04-14 15:29:29 +00001095 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001096 }
1097 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1098 tempNode->setLine(getLine());
1099
1100 return tempNode;
1101 }
1102 else
1103 {
1104 //
1105 // Do unary operations
1106 //
1107 TIntermConstantUnion *newNode = 0;
1108 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1109 for (size_t i = 0; i < objectSize; i++)
1110 {
1111 switch(op)
1112 {
1113 case EOpNegative:
1114 switch (getType().getBasicType())
1115 {
1116 case EbtFloat:
1117 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1118 break;
1119 case EbtInt:
1120 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1121 break;
1122 case EbtUInt:
1123 tempConstArray[i].setUConst(static_cast<unsigned int>(
1124 -static_cast<int>(unionArray[i].getUConst())));
1125 break;
1126 default:
1127 infoSink.info.message(
1128 EPrefixInternalError, getLine(),
1129 "Unary operation not folded into constant");
Jamie Madillb7757782015-04-14 15:29:29 +00001130 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001131 }
1132 break;
1133
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001134 case EOpPositive:
1135 switch (getType().getBasicType())
1136 {
1137 case EbtFloat:
1138 tempConstArray[i].setFConst(unionArray[i].getFConst());
1139 break;
1140 case EbtInt:
1141 tempConstArray[i].setIConst(unionArray[i].getIConst());
1142 break;
1143 case EbtUInt:
1144 tempConstArray[i].setUConst(static_cast<unsigned int>(
1145 static_cast<int>(unionArray[i].getUConst())));
1146 break;
1147 default:
1148 infoSink.info.message(
1149 EPrefixInternalError, getLine(),
1150 "Unary operation not folded into constant");
Jamie Madillb7757782015-04-14 15:29:29 +00001151 return NULL;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001152 }
1153 break;
1154
Jamie Madillb1a85f42014-08-19 15:23:24 -04001155 case EOpLogicalNot:
1156 // this code is written for possible future use,
1157 // will not get executed currently
1158 switch (getType().getBasicType())
1159 {
1160 case EbtBool:
1161 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1162 break;
1163 default:
1164 infoSink.info.message(
1165 EPrefixInternalError, getLine(),
1166 "Unary operation not folded into constant");
Jamie Madillb7757782015-04-14 15:29:29 +00001167 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001168 }
1169 break;
1170
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001171 case EOpBitwiseNot:
1172 switch (getType().getBasicType())
1173 {
1174 case EbtInt:
1175 tempConstArray[i].setIConst(~unionArray[i].getIConst());
1176 break;
1177 case EbtUInt:
1178 tempConstArray[i].setUConst(~unionArray[i].getUConst());
1179 break;
1180 default:
1181 infoSink.info.message(
1182 EPrefixInternalError, getLine(),
1183 "Unary operation not folded into constant");
Jamie Madillb7757782015-04-14 15:29:29 +00001184 return NULL;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001185 }
1186 break;
1187
Jamie Madillb1a85f42014-08-19 15:23:24 -04001188 default:
Jamie Madillb7757782015-04-14 15:29:29 +00001189 return NULL;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001190 }
1191 }
1192 newNode = new TIntermConstantUnion(tempConstArray, getType());
1193 newNode->setLine(getLine());
1194 return newNode;
1195 }
1196}
1197
1198// static
1199TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1200{
1201 if (hashFunction == NULL || name.empty())
1202 return name;
1203 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1204 TStringStream stream;
1205 stream << HASHED_NAME_PREFIX << std::hex << number;
1206 TString hashedName = stream.str();
1207 return hashedName;
1208}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001209
1210void TIntermTraverser::updateTree()
1211{
1212 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
1213 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001214 const NodeUpdateEntry &replacement = mReplacements[ii];
1215 ASSERT(replacement.parent);
1216 bool replaced = replacement.parent->replaceChildNode(
1217 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001218 ASSERT(replaced);
1219
Olli Etuahocd94ef92015-04-16 19:18:10 +03001220 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001221 {
1222 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03001223 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001224 // be replaced, we need to make sure we don't update the replaced
1225 // node; instead, we update the replacement node.
1226 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
1227 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03001228 NodeUpdateEntry &replacement2 = mReplacements[jj];
1229 if (replacement2.parent == replacement.original)
1230 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02001231 }
1232 }
1233 }
1234}