Merge branch 'patch-1' of https://github.com/HaydnTrigg/glslang into HaydnTrigg-patch-1
[platform/upstream/glslang.git] / glslang / MachineIndependent / Constant.cpp
1 //
2 // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 // Copyright (C) 2012-2013 LunarG, Inc.
4 // Copyright (C) 2017 ARM Limited.
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 //
12 //    Redistributions of source code must retain the above copyright
13 //    notice, this list of conditions and the following disclaimer.
14 //
15 //    Redistributions in binary form must reproduce the above
16 //    copyright notice, this list of conditions and the following
17 //    disclaimer in the documentation and/or other materials provided
18 //    with the distribution.
19 //
20 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
21 //    contributors may be used to endorse or promote products derived
22 //    from this software without specific prior written permission.
23 //
24 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 // POSSIBILITY OF SUCH DAMAGE.
36 //
37
38 #include "localintermediate.h"
39 #include <cmath>
40 #include <cfloat>
41 #include <cstdlib>
42 #include <climits>
43
44 namespace {
45
46 using namespace glslang;
47
48 typedef union {
49     double d;
50     int i[2];
51 } DoubleIntUnion;
52
53 // Some helper functions
54
55 bool isNan(double x)
56 {
57     DoubleIntUnion u;
58     // tough to find a platform independent library function, do it directly
59     u.d = x;
60     int bitPatternL = u.i[0];
61     int bitPatternH = u.i[1];
62     return (bitPatternH & 0x7ff80000) == 0x7ff80000 &&
63            ((bitPatternH & 0xFFFFF) != 0 || bitPatternL != 0);
64 }
65
66 bool isInf(double x)
67 {
68     DoubleIntUnion u;
69     // tough to find a platform independent library function, do it directly
70     u.d = x;
71     int bitPatternL = u.i[0];
72     int bitPatternH = u.i[1];
73     return (bitPatternH & 0x7ff00000) == 0x7ff00000 &&
74            (bitPatternH & 0xFFFFF) == 0 && bitPatternL == 0;
75 }
76
77 const double pi = 3.1415926535897932384626433832795;
78
79 } // end anonymous namespace
80
81
82 namespace glslang {
83
84 //
85 // The fold functions see if an operation on a constant can be done in place,
86 // without generating run-time code.
87 //
88 // Returns the node to keep using, which may or may not be the node passed in.
89 //
90 // Note: As of version 1.2, all constant operations must be folded.  It is
91 // not opportunistic, but rather a semantic requirement.
92 //
93
94 //
95 // Do folding between a pair of nodes.
96 // 'this' is the left-hand operand and 'rightConstantNode' is the right-hand operand.
97 //
98 // Returns a new node representing the result.
99 //
100 TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* rightConstantNode) const
101 {
102     // For most cases, the return type matches the argument type, so set that
103     // up and just code to exceptions below.
104     TType returnType;
105     returnType.shallowCopy(getType());
106
107     //
108     // A pair of nodes is to be folded together
109     //
110
111     const TIntermConstantUnion *rightNode = rightConstantNode->getAsConstantUnion();
112     TConstUnionArray leftUnionArray = getConstArray();
113     TConstUnionArray rightUnionArray = rightNode->getConstArray();
114
115     // Figure out the size of the result
116     int newComps;
117     int constComps;
118     switch(op) {
119     case EOpMatrixTimesMatrix:
120         newComps = rightNode->getMatrixCols() * getMatrixRows();
121         break;
122     case EOpMatrixTimesVector:
123         newComps = getMatrixRows();
124         break;
125     case EOpVectorTimesMatrix:
126         newComps = rightNode->getMatrixCols();
127         break;
128     default:
129         newComps = getType().computeNumComponents();
130         constComps = rightConstantNode->getType().computeNumComponents();
131         if (constComps == 1 && newComps > 1) {
132             // for a case like vec4 f = vec4(2,3,4,5) + 1.2;
133             TConstUnionArray smearedArray(newComps, rightNode->getConstArray()[0]);
134             rightUnionArray = smearedArray;
135         } else if (constComps > 1 && newComps == 1) {
136             // for a case like vec4 f = 1.2 + vec4(2,3,4,5);
137             newComps = constComps;
138             rightUnionArray = rightNode->getConstArray();
139             TConstUnionArray smearedArray(newComps, getConstArray()[0]);
140             leftUnionArray = smearedArray;
141             returnType.shallowCopy(rightNode->getType());
142         }
143         break;
144     }
145
146     TConstUnionArray newConstArray(newComps);
147     TType constBool(EbtBool, EvqConst);
148
149     switch(op) {
150     case EOpAdd:
151         for (int i = 0; i < newComps; i++)
152             newConstArray[i] = leftUnionArray[i] + rightUnionArray[i];
153         break;
154     case EOpSub:
155         for (int i = 0; i < newComps; i++)
156             newConstArray[i] = leftUnionArray[i] - rightUnionArray[i];
157         break;
158
159     case EOpMul:
160     case EOpVectorTimesScalar:
161     case EOpMatrixTimesScalar:
162         for (int i = 0; i < newComps; i++)
163             newConstArray[i] = leftUnionArray[i] * rightUnionArray[i];
164         break;
165     case EOpMatrixTimesMatrix:
166         for (int row = 0; row < getMatrixRows(); row++) {
167             for (int column = 0; column < rightNode->getMatrixCols(); column++) {
168                 double sum = 0.0f;
169                 for (int i = 0; i < rightNode->getMatrixRows(); i++)
170                     sum += leftUnionArray[i * getMatrixRows() + row].getDConst() * rightUnionArray[column * rightNode->getMatrixRows() + i].getDConst();
171                 newConstArray[column * getMatrixRows() + row].setDConst(sum);
172             }
173         }
174         returnType.shallowCopy(TType(getType().getBasicType(), EvqConst, 0, rightNode->getMatrixCols(), getMatrixRows()));
175         break;
176     case EOpDiv:
177         for (int i = 0; i < newComps; i++) {
178             switch (getType().getBasicType()) {
179             case EbtDouble:
180             case EbtFloat:
181             case EbtFloat16:
182                 {
183                     auto right = rightUnionArray[i].getDConst();
184                     auto left = leftUnionArray[i].getDConst();
185
186                     if (right)
187                     {
188                         newConstArray[i].setDConst(left / right);
189                     }
190                     else if (left > 0)
191                     {
192                         newConstArray[i].setDConst((double)INFINITY);
193                     }
194                     else if (left < 0)
195                     {
196                         newConstArray[i].setDConst((double)-INFINITY);
197                     }
198                     else
199                     {
200                         newConstArray[i].setDConst((double)NAN);
201                     }
202                 }
203                 break;
204             case EbtInt8:
205                 if (rightUnionArray[i] == (signed char)0)
206                     newConstArray[i].setI8Const((signed char)0x7F);
207                 else if (rightUnionArray[i].getI8Const() == (signed char)-1 && leftUnionArray[i].getI8Const() == (signed char)-0x80)
208                     newConstArray[i].setI8Const((signed char)-0x80);
209                 else
210                     newConstArray[i].setI8Const(leftUnionArray[i].getI8Const() / rightUnionArray[i].getI8Const());
211                 break;
212
213             case EbtUint8:
214                 if (rightUnionArray[i] == (unsigned char)0u)
215                     newConstArray[i].setU8Const((unsigned char)0xFFu);
216                 else
217                     newConstArray[i].setU8Const(leftUnionArray[i].getU8Const() / rightUnionArray[i].getU8Const());
218                 break;
219
220            case EbtInt16:
221                 if (rightUnionArray[i] == (signed short)0)
222                     newConstArray[i].setI16Const((signed short)0x7FFF);
223                 else if (rightUnionArray[i].getI16Const() == (signed short)-1 && leftUnionArray[i].getI16Const() == (signed short)-0x8000)
224                     newConstArray[i].setI16Const((signed short)-0x8000);
225                 else
226                     newConstArray[i].setI16Const(leftUnionArray[i].getI16Const() / rightUnionArray[i].getI16Const());
227                 break;
228
229             case EbtUint16:
230                 if (rightUnionArray[i] == (unsigned short)0u)
231                     newConstArray[i].setU16Const((unsigned short)0xFFFFu);
232                 else
233                     newConstArray[i].setU16Const(leftUnionArray[i].getU16Const() / rightUnionArray[i].getU16Const());
234                 break;
235
236             case EbtInt:
237                 if (rightUnionArray[i] == 0)
238                     newConstArray[i].setIConst(0x7FFFFFFF);
239                 else if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == -(int)0x80000000)
240                     newConstArray[i].setIConst(-(int)0x80000000);
241                 else
242                     newConstArray[i].setIConst(leftUnionArray[i].getIConst() / rightUnionArray[i].getIConst());
243                 break;
244
245             case EbtUint:
246                 if (rightUnionArray[i] == 0u)
247                     newConstArray[i].setUConst(0xFFFFFFFFu);
248                 else
249                     newConstArray[i].setUConst(leftUnionArray[i].getUConst() / rightUnionArray[i].getUConst());
250                 break;
251
252             case EbtInt64:
253                 if (rightUnionArray[i] == 0ll)
254                     newConstArray[i].setI64Const(0x7FFFFFFFFFFFFFFFll);
255                 else if (rightUnionArray[i].getI64Const() == -1 && leftUnionArray[i].getI64Const() == -0x8000000000000000ll)
256                     newConstArray[i].setI64Const(-0x8000000000000000ll);
257                 else
258                     newConstArray[i].setI64Const(leftUnionArray[i].getI64Const() / rightUnionArray[i].getI64Const());
259                 break;
260
261             case EbtUint64:
262                 if (rightUnionArray[i] == 0ull)
263                     newConstArray[i].setU64Const(0xFFFFFFFFFFFFFFFFull);
264                 else
265                     newConstArray[i].setU64Const(leftUnionArray[i].getU64Const() / rightUnionArray[i].getU64Const());
266                 break;
267             default:
268                 return 0;
269             }
270         }
271         break;
272
273     case EOpMatrixTimesVector:
274         for (int i = 0; i < getMatrixRows(); i++) {
275             double sum = 0.0f;
276             for (int j = 0; j < rightNode->getVectorSize(); j++) {
277                 sum += leftUnionArray[j*getMatrixRows() + i].getDConst() * rightUnionArray[j].getDConst();
278             }
279             newConstArray[i].setDConst(sum);
280         }
281
282         returnType.shallowCopy(TType(getBasicType(), EvqConst, getMatrixRows()));
283         break;
284
285     case EOpVectorTimesMatrix:
286         for (int i = 0; i < rightNode->getMatrixCols(); i++) {
287             double sum = 0.0f;
288             for (int j = 0; j < getVectorSize(); j++)
289                 sum += leftUnionArray[j].getDConst() * rightUnionArray[i*rightNode->getMatrixRows() + j].getDConst();
290             newConstArray[i].setDConst(sum);
291         }
292
293         returnType.shallowCopy(TType(getBasicType(), EvqConst, rightNode->getMatrixCols()));
294         break;
295
296     case EOpMod:
297         for (int i = 0; i < newComps; i++) {
298             if (rightUnionArray[i] == 0)
299                 newConstArray[i] = leftUnionArray[i];
300             else {
301                 switch (getType().getBasicType()) {
302                 case EbtInt:
303                     if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == INT_MIN) {
304                         newConstArray[i].setIConst(0);
305                         break;
306                     } else goto modulo_default;
307
308                 case EbtInt64:
309                     if (rightUnionArray[i].getI64Const() == -1 && leftUnionArray[i].getI64Const() == LLONG_MIN) {
310                         newConstArray[i].setI64Const(0);
311                         break;
312                     } else goto modulo_default;
313 #ifdef AMD_EXTENSIONS
314                 case EbtInt16:
315                     if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == SHRT_MIN) {
316                         newConstArray[i].setIConst(0);
317                         break;
318                     } else goto modulo_default;
319 #endif
320                 default:
321                 modulo_default:
322                     newConstArray[i] = leftUnionArray[i] % rightUnionArray[i];
323                 }
324             }
325         }
326         break;
327
328     case EOpRightShift:
329         for (int i = 0; i < newComps; i++)
330             newConstArray[i] = leftUnionArray[i] >> rightUnionArray[i];
331         break;
332
333     case EOpLeftShift:
334         for (int i = 0; i < newComps; i++)
335             newConstArray[i] = leftUnionArray[i] << rightUnionArray[i];
336         break;
337
338     case EOpAnd:
339         for (int i = 0; i < newComps; i++)
340             newConstArray[i] = leftUnionArray[i] & rightUnionArray[i];
341         break;
342     case EOpInclusiveOr:
343         for (int i = 0; i < newComps; i++)
344             newConstArray[i] = leftUnionArray[i] | rightUnionArray[i];
345         break;
346     case EOpExclusiveOr:
347         for (int i = 0; i < newComps; i++)
348             newConstArray[i] = leftUnionArray[i] ^ rightUnionArray[i];
349         break;
350
351     case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
352         for (int i = 0; i < newComps; i++)
353             newConstArray[i] = leftUnionArray[i] && rightUnionArray[i];
354         break;
355
356     case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
357         for (int i = 0; i < newComps; i++)
358             newConstArray[i] = leftUnionArray[i] || rightUnionArray[i];
359         break;
360
361     case EOpLogicalXor:
362         for (int i = 0; i < newComps; i++) {
363             switch (getType().getBasicType()) {
364             case EbtBool: newConstArray[i].setBConst((leftUnionArray[i] == rightUnionArray[i]) ? false : true); break;
365             default: assert(false && "Default missing");
366             }
367         }
368         break;
369
370     case EOpLessThan:
371         newConstArray[0].setBConst(leftUnionArray[0] < rightUnionArray[0]);
372         returnType.shallowCopy(constBool);
373         break;
374     case EOpGreaterThan:
375         newConstArray[0].setBConst(leftUnionArray[0] > rightUnionArray[0]);
376         returnType.shallowCopy(constBool);
377         break;
378     case EOpLessThanEqual:
379         newConstArray[0].setBConst(! (leftUnionArray[0] > rightUnionArray[0]));
380         returnType.shallowCopy(constBool);
381         break;
382     case EOpGreaterThanEqual:
383         newConstArray[0].setBConst(! (leftUnionArray[0] < rightUnionArray[0]));
384         returnType.shallowCopy(constBool);
385         break;
386     case EOpEqual:
387         newConstArray[0].setBConst(rightNode->getConstArray() == leftUnionArray);
388         returnType.shallowCopy(constBool);
389         break;
390     case EOpNotEqual:
391         newConstArray[0].setBConst(rightNode->getConstArray() != leftUnionArray);
392         returnType.shallowCopy(constBool);
393         break;
394
395     default:
396         return 0;
397     }
398
399     TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType);
400     newNode->setLoc(getLoc());
401
402     return newNode;
403 }
404
405 //
406 // Do single unary node folding
407 //
408 // Returns a new node representing the result.
409 //
410 TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) const
411 {
412     // First, size the result, which is mostly the same as the argument's size,
413     // but not always, and classify what is componentwise.
414     // Also, eliminate cases that can't be compile-time constant.
415     int resultSize;
416     bool componentWise = true;
417
418     int objectSize = getType().computeNumComponents();
419     switch (op) {
420     case EOpDeterminant:
421     case EOpAny:
422     case EOpAll:
423     case EOpLength:
424         componentWise = false;
425         resultSize = 1;
426         break;
427
428     case EOpEmitStreamVertex:
429     case EOpEndStreamPrimitive:
430         // These don't actually fold
431         return 0;
432
433     case EOpPackSnorm2x16:
434     case EOpPackUnorm2x16:
435     case EOpPackHalf2x16:
436         componentWise = false;
437         resultSize = 1;
438         break;
439
440     case EOpUnpackSnorm2x16:
441     case EOpUnpackUnorm2x16:
442     case EOpUnpackHalf2x16:
443         componentWise = false;
444         resultSize = 2;
445         break;
446
447     case EOpPack16:
448     case EOpPack32:
449     case EOpPack64:
450     case EOpUnpack32:
451     case EOpUnpack16:
452     case EOpUnpack8:
453     case EOpNormalize:
454         componentWise = false;
455         resultSize = objectSize;
456         break;
457
458     default:
459         resultSize = objectSize;
460         break;
461     }
462
463     // Set up for processing
464     TConstUnionArray newConstArray(resultSize);
465     const TConstUnionArray& unionArray = getConstArray();
466
467     // Process non-component-wise operations
468     switch (op) {
469     case EOpLength:
470     case EOpNormalize:
471     {
472         double sum = 0;
473         for (int i = 0; i < objectSize; i++)
474             sum += unionArray[i].getDConst() * unionArray[i].getDConst();
475         double length = sqrt(sum);
476         if (op == EOpLength)
477             newConstArray[0].setDConst(length);
478         else {
479             for (int i = 0; i < objectSize; i++)
480                 newConstArray[i].setDConst(unionArray[i].getDConst() / length);
481         }
482         break;
483     }
484
485     case EOpAny:
486     {
487         bool result = false;
488         for (int i = 0; i < objectSize; i++) {
489             if (unionArray[i].getBConst())
490                 result = true;
491         }
492         newConstArray[0].setBConst(result);
493         break;
494     }
495     case EOpAll:
496     {
497         bool result = true;
498         for (int i = 0; i < objectSize; i++) {
499             if (! unionArray[i].getBConst())
500                 result = false;
501         }
502         newConstArray[0].setBConst(result);
503         break;
504     }
505
506     // TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out
507
508     case EOpPackSnorm2x16:
509     case EOpPackUnorm2x16:
510     case EOpPackHalf2x16:
511     case EOpPack16:
512     case EOpPack32:
513     case EOpPack64:
514     case EOpUnpack32:
515     case EOpUnpack16:
516     case EOpUnpack8:
517
518     case EOpUnpackSnorm2x16:
519     case EOpUnpackUnorm2x16:
520     case EOpUnpackHalf2x16:
521
522     case EOpDeterminant:
523     case EOpMatrixInverse:
524     case EOpTranspose:
525         return 0;
526
527     default:
528         assert(componentWise);
529         break;
530     }
531
532     // Turn off the componentwise loop
533     if (! componentWise)
534         objectSize = 0;
535
536     // Process component-wise operations
537     for (int i = 0; i < objectSize; i++) {
538         switch (op) {
539         case EOpNegative:
540             switch (getType().getBasicType()) {
541             case EbtDouble:
542             case EbtFloat16:
543             case EbtFloat: newConstArray[i].setDConst(-unionArray[i].getDConst()); break;
544             case EbtInt8:  newConstArray[i].setI8Const(-unionArray[i].getI8Const()); break;
545             case EbtUint8: newConstArray[i].setU8Const(static_cast<unsigned int>(-static_cast<signed int>(unionArray[i].getU8Const())));  break;
546             case EbtInt16: newConstArray[i].setI16Const(-unionArray[i].getI16Const()); break;
547             case EbtUint16:newConstArray[i].setU16Const(static_cast<unsigned int>(-static_cast<signed int>(unionArray[i].getU16Const())));  break;
548             case EbtInt:   newConstArray[i].setIConst(-unionArray[i].getIConst()); break;
549             case EbtUint:  newConstArray[i].setUConst(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getUConst())));  break;
550             case EbtInt64: newConstArray[i].setI64Const(-unionArray[i].getI64Const()); break;
551             case EbtUint64: newConstArray[i].setU64Const(static_cast<unsigned long long>(-static_cast<long long>(unionArray[i].getU64Const())));  break;
552             default:
553                 return 0;
554             }
555             break;
556         case EOpLogicalNot:
557         case EOpVectorLogicalNot:
558             switch (getType().getBasicType()) {
559             case EbtBool:  newConstArray[i].setBConst(!unionArray[i].getBConst()); break;
560             default:
561                 return 0;
562             }
563             break;
564         case EOpBitwiseNot:
565             newConstArray[i] = ~unionArray[i];
566             break;
567         case EOpRadians:
568             newConstArray[i].setDConst(unionArray[i].getDConst() * pi / 180.0);
569             break;
570         case EOpDegrees:
571             newConstArray[i].setDConst(unionArray[i].getDConst() * 180.0 / pi);
572             break;
573         case EOpSin:
574             newConstArray[i].setDConst(sin(unionArray[i].getDConst()));
575             break;
576         case EOpCos:
577             newConstArray[i].setDConst(cos(unionArray[i].getDConst()));
578             break;
579         case EOpTan:
580             newConstArray[i].setDConst(tan(unionArray[i].getDConst()));
581             break;
582         case EOpAsin:
583             newConstArray[i].setDConst(asin(unionArray[i].getDConst()));
584             break;
585         case EOpAcos:
586             newConstArray[i].setDConst(acos(unionArray[i].getDConst()));
587             break;
588         case EOpAtan:
589             newConstArray[i].setDConst(atan(unionArray[i].getDConst()));
590             break;
591
592         case EOpDPdx:
593         case EOpDPdy:
594         case EOpFwidth:
595         case EOpDPdxFine:
596         case EOpDPdyFine:
597         case EOpFwidthFine:
598         case EOpDPdxCoarse:
599         case EOpDPdyCoarse:
600         case EOpFwidthCoarse:
601             // The derivatives are all mandated to create a constant 0.
602             newConstArray[i].setDConst(0.0);
603             break;
604
605         case EOpExp:
606             newConstArray[i].setDConst(exp(unionArray[i].getDConst()));
607             break;
608         case EOpLog:
609             newConstArray[i].setDConst(log(unionArray[i].getDConst()));
610             break;
611         case EOpExp2:
612             {
613                 const double inv_log2_e = 0.69314718055994530941723212145818;
614                 newConstArray[i].setDConst(exp(unionArray[i].getDConst() * inv_log2_e));
615                 break;
616             }
617         case EOpLog2:
618             {
619                 const double log2_e = 1.4426950408889634073599246810019;
620                 newConstArray[i].setDConst(log2_e * log(unionArray[i].getDConst()));
621                 break;
622             }
623         case EOpSqrt:
624             newConstArray[i].setDConst(sqrt(unionArray[i].getDConst()));
625             break;
626         case EOpInverseSqrt:
627             newConstArray[i].setDConst(1.0 / sqrt(unionArray[i].getDConst()));
628             break;
629
630         case EOpAbs:
631             if (unionArray[i].getType() == EbtDouble)
632                 newConstArray[i].setDConst(fabs(unionArray[i].getDConst()));
633             else if (unionArray[i].getType() == EbtInt)
634                 newConstArray[i].setIConst(abs(unionArray[i].getIConst()));
635             else
636                 newConstArray[i] = unionArray[i];
637             break;
638         case EOpSign:
639             #define SIGN(X) (X == 0 ? 0 : (X < 0 ? -1 : 1))
640             if (unionArray[i].getType() == EbtDouble)
641                 newConstArray[i].setDConst(SIGN(unionArray[i].getDConst()));
642             else
643                 newConstArray[i].setIConst(SIGN(unionArray[i].getIConst()));
644             break;
645         case EOpFloor:
646             newConstArray[i].setDConst(floor(unionArray[i].getDConst()));
647             break;
648         case EOpTrunc:
649             if (unionArray[i].getDConst() > 0)
650                 newConstArray[i].setDConst(floor(unionArray[i].getDConst()));
651             else
652                 newConstArray[i].setDConst(ceil(unionArray[i].getDConst()));
653             break;
654         case EOpRound:
655             newConstArray[i].setDConst(floor(0.5 + unionArray[i].getDConst()));
656             break;
657         case EOpRoundEven:
658         {
659             double flr = floor(unionArray[i].getDConst());
660             bool even = flr / 2.0 == floor(flr / 2.0);
661             double rounded = even ? ceil(unionArray[i].getDConst() - 0.5) : floor(unionArray[i].getDConst() + 0.5);
662             newConstArray[i].setDConst(rounded);
663             break;
664         }
665         case EOpCeil:
666             newConstArray[i].setDConst(ceil(unionArray[i].getDConst()));
667             break;
668         case EOpFract:
669         {
670             double x = unionArray[i].getDConst();
671             newConstArray[i].setDConst(x - floor(x));
672             break;
673         }
674
675         case EOpIsNan:
676         {
677             newConstArray[i].setBConst(isNan(unionArray[i].getDConst()));
678             break;
679         }
680         case EOpIsInf:
681         {
682             newConstArray[i].setBConst(isInf(unionArray[i].getDConst()));
683             break;
684         }
685
686         // TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out
687
688         case EOpSinh:
689         case EOpCosh:
690         case EOpTanh:
691         case EOpAsinh:
692         case EOpAcosh:
693         case EOpAtanh:
694
695         case EOpFloatBitsToInt:
696         case EOpFloatBitsToUint:
697         case EOpIntBitsToFloat:
698         case EOpUintBitsToFloat:
699         case EOpDoubleBitsToInt64:
700         case EOpDoubleBitsToUint64:
701         case EOpInt64BitsToDouble:
702         case EOpUint64BitsToDouble:
703         case EOpFloat16BitsToInt16:
704         case EOpFloat16BitsToUint16:
705         case EOpInt16BitsToFloat16:
706         case EOpUint16BitsToFloat16:
707         default:
708             return 0;
709         }
710     }
711
712     TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType);
713     newNode->getWritableType().getQualifier().storage = EvqConst;
714     newNode->setLoc(getLoc());
715
716     return newNode;
717 }
718
719 //
720 // Do constant folding for an aggregate node that has all its children
721 // as constants and an operator that requires constant folding.
722 //
723 TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
724 {
725     if (aggrNode == nullptr)
726         return aggrNode;
727
728     if (! areAllChildConst(aggrNode))
729         return aggrNode;
730
731     if (aggrNode->isConstructor())
732         return foldConstructor(aggrNode);
733
734     TIntermSequence& children = aggrNode->getSequence();
735
736     // First, see if this is an operation to constant fold, kick out if not,
737     // see what size the result is if so.
738
739     bool componentwise = false;  // will also say componentwise if a scalar argument gets repeated to make per-component results
740     int objectSize;
741     switch (aggrNode->getOp()) {
742     case EOpAtan:
743     case EOpPow:
744     case EOpMin:
745     case EOpMax:
746     case EOpMix:
747     case EOpClamp:
748     case EOpLessThan:
749     case EOpGreaterThan:
750     case EOpLessThanEqual:
751     case EOpGreaterThanEqual:
752     case EOpVectorEqual:
753     case EOpVectorNotEqual:
754         componentwise = true;
755         objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
756         break;
757     case EOpCross:
758     case EOpReflect:
759     case EOpRefract:
760     case EOpFaceForward:
761         objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
762         break;
763     case EOpDistance:
764     case EOpDot:
765         objectSize = 1;
766         break;
767     case EOpOuterProduct:
768         objectSize = children[0]->getAsTyped()->getType().getVectorSize() *
769                      children[1]->getAsTyped()->getType().getVectorSize();
770         break;
771     case EOpStep:
772         componentwise = true;
773         objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(),
774                               children[1]->getAsTyped()->getType().getVectorSize());
775         break;
776     case EOpSmoothStep:
777         componentwise = true;
778         objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(),
779                               children[2]->getAsTyped()->getType().getVectorSize());
780         break;
781     default:
782         return aggrNode;
783     }
784     TConstUnionArray newConstArray(objectSize);
785
786     TVector<TConstUnionArray> childConstUnions;
787     for (unsigned int arg = 0; arg < children.size(); ++arg)
788         childConstUnions.push_back(children[arg]->getAsConstantUnion()->getConstArray());
789
790     if (componentwise) {
791         for (int comp = 0; comp < objectSize; comp++) {
792
793             // some arguments are scalars instead of matching vectors; simulate a smear
794             int arg0comp = std::min(comp, children[0]->getAsTyped()->getType().getVectorSize() - 1);
795             int arg1comp = 0;
796             if (children.size() > 1)
797                 arg1comp = std::min(comp, children[1]->getAsTyped()->getType().getVectorSize() - 1);
798             int arg2comp = 0;
799             if (children.size() > 2)
800                 arg2comp = std::min(comp, children[2]->getAsTyped()->getType().getVectorSize() - 1);
801
802             switch (aggrNode->getOp()) {
803             case EOpAtan:
804                 newConstArray[comp].setDConst(atan2(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
805                 break;
806             case EOpPow:
807                 newConstArray[comp].setDConst(pow(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
808                 break;
809             case EOpMin:
810                 switch(children[0]->getAsTyped()->getBasicType()) {
811                 case EbtFloat16:
812                 case EbtFloat:
813                 case EbtDouble:
814                     newConstArray[comp].setDConst(std::min(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
815                     break;
816                 case EbtInt8:
817                     newConstArray[comp].setI8Const(std::min(childConstUnions[0][arg0comp].getI8Const(), childConstUnions[1][arg1comp].getI8Const()));
818                     break;
819                 case EbtUint8:
820                     newConstArray[comp].setU8Const(std::min(childConstUnions[0][arg0comp].getU8Const(), childConstUnions[1][arg1comp].getU8Const()));
821                     break;
822                 case EbtInt16:
823                     newConstArray[comp].setI16Const(std::min(childConstUnions[0][arg0comp].getI16Const(), childConstUnions[1][arg1comp].getI16Const()));
824                     break;
825                 case EbtUint16:
826                     newConstArray[comp].setU16Const(std::min(childConstUnions[0][arg0comp].getU16Const(), childConstUnions[1][arg1comp].getU16Const()));
827                     break;
828                 case EbtInt:
829                     newConstArray[comp].setIConst(std::min(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()));
830                     break;
831                 case EbtUint:
832                     newConstArray[comp].setUConst(std::min(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()));
833                     break;
834                 case EbtInt64:
835                     newConstArray[comp].setI64Const(std::min(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()));
836                     break;
837                 case EbtUint64:
838                     newConstArray[comp].setU64Const(std::min(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()));
839                     break;
840                 default: assert(false && "Default missing");
841                 }
842                 break;
843             case EOpMax:
844                 switch(children[0]->getAsTyped()->getBasicType()) {
845                 case EbtFloat16:
846                 case EbtFloat:
847                 case EbtDouble:
848                     newConstArray[comp].setDConst(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
849                     break;
850                 case EbtInt8:
851                     newConstArray[comp].setI8Const(std::max(childConstUnions[0][arg0comp].getI8Const(), childConstUnions[1][arg1comp].getI8Const()));
852                     break;
853                 case EbtUint8:
854                     newConstArray[comp].setU8Const(std::max(childConstUnions[0][arg0comp].getU8Const(), childConstUnions[1][arg1comp].getU8Const()));
855                     break;
856                 case EbtInt16:
857                     newConstArray[comp].setI16Const(std::max(childConstUnions[0][arg0comp].getI16Const(), childConstUnions[1][arg1comp].getI16Const()));
858                     break;
859                 case EbtUint16:
860                     newConstArray[comp].setU16Const(std::max(childConstUnions[0][arg0comp].getU16Const(), childConstUnions[1][arg1comp].getU16Const()));
861                     break;
862                 case EbtInt:
863                     newConstArray[comp].setIConst(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()));
864                     break;
865                 case EbtUint:
866                     newConstArray[comp].setUConst(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()));
867                     break;
868                 case EbtInt64:
869                     newConstArray[comp].setI64Const(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()));
870                     break;
871                 case EbtUint64:
872                     newConstArray[comp].setU64Const(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()));
873                     break;
874                 default: assert(false && "Default missing");
875                 }
876                 break;
877             case EOpClamp:
878                 switch(children[0]->getAsTyped()->getBasicType()) {
879                 case EbtFloat16:
880                 case EbtFloat:
881                 case EbtDouble:
882                     newConstArray[comp].setDConst(std::min(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()),
883                                                                                                                childConstUnions[2][arg2comp].getDConst()));
884                     break;
885                 case EbtInt8:
886                     newConstArray[comp].setI8Const(std::min(std::max(childConstUnions[0][arg0comp].getI8Const(), childConstUnions[1][arg1comp].getI8Const()),
887                                                                                                                    childConstUnions[2][arg2comp].getI8Const()));
888                     break;
889                 case EbtUint8:
890                      newConstArray[comp].setU8Const(std::min(std::max(childConstUnions[0][arg0comp].getU8Const(), childConstUnions[1][arg1comp].getU8Const()),
891                                                                                                                    childConstUnions[2][arg2comp].getU8Const()));
892                     break;
893                 case EbtInt16:
894                     newConstArray[comp].setI16Const(std::min(std::max(childConstUnions[0][arg0comp].getI16Const(), childConstUnions[1][arg1comp].getI16Const()),
895                                                                                                                    childConstUnions[2][arg2comp].getI16Const()));
896                     break;
897                 case EbtUint16:
898                     newConstArray[comp].setU16Const(std::min(std::max(childConstUnions[0][arg0comp].getU16Const(), childConstUnions[1][arg1comp].getU16Const()),
899                                                                                                                    childConstUnions[2][arg2comp].getU16Const()));
900                     break;
901                 case EbtInt:
902                     newConstArray[comp].setIConst(std::min(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()),
903                                                                                                                    childConstUnions[2][arg2comp].getIConst()));
904                     break;
905                 case EbtUint:
906                     newConstArray[comp].setUConst(std::min(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()),
907                                                                                                                    childConstUnions[2][arg2comp].getUConst()));
908                     break;
909                 case EbtInt64:
910                     newConstArray[comp].setI64Const(std::min(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()),
911                                                                                                                        childConstUnions[2][arg2comp].getI64Const()));
912                     break;
913                 case EbtUint64:
914                     newConstArray[comp].setU64Const(std::min(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()),
915                                                                                                                        childConstUnions[2][arg2comp].getU64Const()));
916                     break;
917                 default: assert(false && "Default missing");
918                 }
919                 break;
920             case EOpLessThan:
921                 newConstArray[comp].setBConst(childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp]);
922                 break;
923             case EOpGreaterThan:
924                 newConstArray[comp].setBConst(childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp]);
925                 break;
926             case EOpLessThanEqual:
927                 newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp]));
928                 break;
929             case EOpGreaterThanEqual:
930                 newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp]));
931                 break;
932             case EOpVectorEqual:
933                 newConstArray[comp].setBConst(childConstUnions[0][arg0comp] == childConstUnions[1][arg1comp]);
934                 break;
935             case EOpVectorNotEqual:
936                 newConstArray[comp].setBConst(childConstUnions[0][arg0comp] != childConstUnions[1][arg1comp]);
937                 break;
938             case EOpMix:
939                 if (children[2]->getAsTyped()->getBasicType() == EbtBool)
940                     newConstArray[comp].setDConst(childConstUnions[2][arg2comp].getBConst() ? childConstUnions[1][arg1comp].getDConst() :
941                                                                                               childConstUnions[0][arg0comp].getDConst());
942                 else
943                     newConstArray[comp].setDConst(childConstUnions[0][arg0comp].getDConst() * (1.0 - childConstUnions[2][arg2comp].getDConst()) +
944                                                   childConstUnions[1][arg1comp].getDConst() *        childConstUnions[2][arg2comp].getDConst());
945                 break;
946             case EOpStep:
947                 newConstArray[comp].setDConst(childConstUnions[1][arg1comp].getDConst() < childConstUnions[0][arg0comp].getDConst() ? 0.0 : 1.0);
948                 break;
949             case EOpSmoothStep:
950             {
951                 double t = (childConstUnions[2][arg2comp].getDConst() - childConstUnions[0][arg0comp].getDConst()) /
952                            (childConstUnions[1][arg1comp].getDConst() - childConstUnions[0][arg0comp].getDConst());
953                 if (t < 0.0)
954                     t = 0.0;
955                 if (t > 1.0)
956                     t = 1.0;
957                 newConstArray[comp].setDConst(t * t * (3.0 - 2.0 * t));
958                 break;
959             }
960             default:
961                 return aggrNode;
962             }
963         }
964     } else {
965         // Non-componentwise...
966
967         int numComps = children[0]->getAsConstantUnion()->getType().computeNumComponents();
968         double dot;
969
970         switch (aggrNode->getOp()) {
971         case EOpDistance:
972         {
973             double sum = 0.0;
974             for (int comp = 0; comp < numComps; ++comp) {
975                 double diff = childConstUnions[1][comp].getDConst() - childConstUnions[0][comp].getDConst();
976                 sum += diff * diff;
977             }
978             newConstArray[0].setDConst(sqrt(sum));
979             break;
980         }
981         case EOpDot:
982             newConstArray[0].setDConst(childConstUnions[0].dot(childConstUnions[1]));
983             break;
984         case EOpCross:
985             newConstArray[0] = childConstUnions[0][1] * childConstUnions[1][2] - childConstUnions[0][2] * childConstUnions[1][1];
986             newConstArray[1] = childConstUnions[0][2] * childConstUnions[1][0] - childConstUnions[0][0] * childConstUnions[1][2];
987             newConstArray[2] = childConstUnions[0][0] * childConstUnions[1][1] - childConstUnions[0][1] * childConstUnions[1][0];
988             break;
989         case EOpFaceForward:
990             // If dot(Nref, I) < 0 return N, otherwise return -N:  Arguments are (N, I, Nref).
991             dot = childConstUnions[1].dot(childConstUnions[2]);
992             for (int comp = 0; comp < numComps; ++comp) {
993                 if (dot < 0.0)
994                     newConstArray[comp] = childConstUnions[0][comp];
995                 else
996                     newConstArray[comp].setDConst(-childConstUnions[0][comp].getDConst());
997             }
998             break;
999         case EOpReflect:
1000             // I - 2 * dot(N, I) * N:  Arguments are (I, N).
1001             dot = childConstUnions[0].dot(childConstUnions[1]);
1002             dot *= 2.0;
1003             for (int comp = 0; comp < numComps; ++comp)
1004                 newConstArray[comp].setDConst(childConstUnions[0][comp].getDConst() - dot * childConstUnions[1][comp].getDConst());
1005             break;
1006         case EOpRefract:
1007         {
1008             // Arguments are (I, N, eta).
1009             // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
1010             // if (k < 0.0)
1011             //     return dvec(0.0)
1012             // else
1013             //     return eta * I - (eta * dot(N, I) + sqrt(k)) * N
1014             dot = childConstUnions[0].dot(childConstUnions[1]);
1015             double eta = childConstUnions[2][0].getDConst();
1016             double k = 1.0 - eta * eta * (1.0 - dot * dot);
1017             if (k < 0.0) {
1018                 for (int comp = 0; comp < numComps; ++comp)
1019                     newConstArray[comp].setDConst(0.0);
1020             } else {
1021                 for (int comp = 0; comp < numComps; ++comp)
1022                     newConstArray[comp].setDConst(eta * childConstUnions[0][comp].getDConst() - (eta * dot + sqrt(k)) * childConstUnions[1][comp].getDConst());
1023             }
1024             break;
1025         }
1026         case EOpOuterProduct:
1027         {
1028             int numRows = numComps;
1029             int numCols = children[1]->getAsConstantUnion()->getType().computeNumComponents();
1030             for (int row = 0; row < numRows; ++row)
1031                 for (int col = 0; col < numCols; ++col)
1032                     newConstArray[col * numRows + row] = childConstUnions[0][row] * childConstUnions[1][col];
1033             break;
1034         }
1035         default:
1036             return aggrNode;
1037         }
1038     }
1039
1040     TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, aggrNode->getType());
1041     newNode->getWritableType().getQualifier().storage = EvqConst;
1042     newNode->setLoc(aggrNode->getLoc());
1043
1044     return newNode;
1045 }
1046
1047 bool TIntermediate::areAllChildConst(TIntermAggregate* aggrNode)
1048 {
1049     bool allConstant = true;
1050
1051     // check if all the child nodes are constants so that they can be inserted into
1052     // the parent node
1053     if (aggrNode) {
1054         TIntermSequence& childSequenceVector = aggrNode->getSequence();
1055         for (TIntermSequence::iterator p  = childSequenceVector.begin();
1056                                        p != childSequenceVector.end(); p++) {
1057             if (!(*p)->getAsTyped()->getAsConstantUnion())
1058                 return false;
1059         }
1060     }
1061
1062     return allConstant;
1063 }
1064
1065 TIntermTyped* TIntermediate::foldConstructor(TIntermAggregate* aggrNode)
1066 {
1067     bool error = false;
1068
1069     TConstUnionArray unionArray(aggrNode->getType().computeNumComponents());
1070     if (aggrNode->getSequence().size() == 1)
1071         error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
1072     else
1073         error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType());
1074
1075     if (error)
1076         return aggrNode;
1077
1078     return addConstantUnion(unionArray, aggrNode->getType(), aggrNode->getLoc());
1079 }
1080
1081 //
1082 // Constant folding of a bracket (array-style) dereference or struct-like dot
1083 // dereference.  Can handle anything except a multi-character swizzle, though
1084 // all swizzles may go to foldSwizzle().
1085 //
1086 TIntermTyped* TIntermediate::foldDereference(TIntermTyped* node, int index, const TSourceLoc& loc)
1087 {
1088     TType dereferencedType(node->getType(), index);
1089     dereferencedType.getQualifier().storage = EvqConst;
1090     TIntermTyped* result = 0;
1091     int size = dereferencedType.computeNumComponents();
1092
1093     // arrays, vectors, matrices, all use simple multiplicative math
1094     // while structures need to add up heterogeneous members
1095     int start;
1096     if (node->isArray() || ! node->isStruct())
1097         start = size * index;
1098     else {
1099         // it is a structure
1100         assert(node->isStruct());
1101         start = 0;
1102         for (int i = 0; i < index; ++i)
1103             start += (*node->getType().getStruct())[i].type->computeNumComponents();
1104     }
1105
1106     result = addConstantUnion(TConstUnionArray(node->getAsConstantUnion()->getConstArray(), start, size), node->getType(), loc);
1107
1108     if (result == 0)
1109         result = node;
1110     else
1111         result->setType(dereferencedType);
1112
1113     return result;
1114 }
1115
1116 //
1117 // Make a constant vector node or constant scalar node, representing a given
1118 // constant vector and constant swizzle into it.
1119 //
1120 TIntermTyped* TIntermediate::foldSwizzle(TIntermTyped* node, TSwizzleSelectors<TVectorSelector>& selectors, const TSourceLoc& loc)
1121 {
1122     const TConstUnionArray& unionArray = node->getAsConstantUnion()->getConstArray();
1123     TConstUnionArray constArray(selectors.size());
1124
1125     for (int i = 0; i < selectors.size(); i++)
1126         constArray[i] = unionArray[selectors[i]];
1127
1128     TIntermTyped* result = addConstantUnion(constArray, node->getType(), loc);
1129
1130     if (result == 0)
1131         result = node;
1132     else
1133         result->setType(TType(node->getBasicType(), EvqConst, selectors.size()));
1134
1135     return result;
1136 }
1137
1138 } // end namespace glslang