1 //
2 // Copyright 2016 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 // ConstantUnion: Constant folding helper class.
7
8 #include "compiler/translator/ConstantUnion.h"
9
10 #include "common/mathutil.h"
11 #include "compiler/translator/Diagnostics.h"
12 #include "compiler/translator/util.h"
13
14 namespace sh
15 {
16
17 namespace
18 {
19
CheckedSum(float lhs,float rhs,TDiagnostics * diag,const TSourceLoc & line)20 float CheckedSum(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
21 {
22 float result = lhs + rhs;
23 if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
24 {
25 diag->warning(line, "Constant folded undefined addition generated NaN", "+");
26 }
27 else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
28 {
29 diag->warning(line, "Constant folded addition overflowed to infinity", "+");
30 }
31 return result;
32 }
33
CheckedDiff(float lhs,float rhs,TDiagnostics * diag,const TSourceLoc & line)34 float CheckedDiff(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
35 {
36 float result = lhs - rhs;
37 if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
38 {
39 diag->warning(line, "Constant folded undefined subtraction generated NaN", "-");
40 }
41 else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
42 {
43 diag->warning(line, "Constant folded subtraction overflowed to infinity", "-");
44 }
45 return result;
46 }
47
CheckedMul(float lhs,float rhs,TDiagnostics * diag,const TSourceLoc & line)48 float CheckedMul(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
49 {
50 float result = lhs * rhs;
51 if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
52 {
53 diag->warning(line, "Constant folded undefined multiplication generated NaN", "*");
54 }
55 else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
56 {
57 diag->warning(line, "Constant folded multiplication overflowed to infinity", "*");
58 }
59 return result;
60 }
61
IsValidShiftOffset(const TConstantUnion & rhs)62 bool IsValidShiftOffset(const TConstantUnion &rhs)
63 {
64 return (rhs.getType() == EbtInt && (rhs.getIConst() >= 0 && rhs.getIConst() <= 31)) ||
65 (rhs.getType() == EbtUInt && rhs.getUConst() <= 31u);
66 }
67
68 } // anonymous namespace
69
TConstantUnion()70 TConstantUnion::TConstantUnion()
71 {
72 iConst = 0;
73 type = EbtVoid;
74 }
75
getIConst() const76 int TConstantUnion::getIConst() const
77 {
78 ASSERT(type == EbtInt);
79 return iConst;
80 }
81
getUConst() const82 unsigned int TConstantUnion::getUConst() const
83 {
84 ASSERT(type == EbtUInt);
85 return uConst;
86 }
87
getFConst() const88 float TConstantUnion::getFConst() const
89 {
90 switch (type)
91 {
92 case EbtInt:
93 return static_cast<float>(iConst);
94 case EbtUInt:
95 return static_cast<float>(uConst);
96 default:
97 ASSERT(type == EbtFloat);
98 return fConst;
99 }
100 }
101
getBConst() const102 bool TConstantUnion::getBConst() const
103 {
104 ASSERT(type == EbtBool);
105 return bConst;
106 }
107
isZero() const108 bool TConstantUnion::isZero() const
109 {
110 switch (type)
111 {
112 case EbtInt:
113 return getIConst() == 0;
114 case EbtUInt:
115 return getUConst() == 0;
116 case EbtFloat:
117 return getFConst() == 0.0f;
118 case EbtBool:
119 return getBConst() == false;
120 default:
121 return false;
122 }
123 }
124
getYuvCscStandardEXTConst() const125 TYuvCscStandardEXT TConstantUnion::getYuvCscStandardEXTConst() const
126 {
127 ASSERT(type == EbtYuvCscStandardEXT);
128 return yuvCscStandardEXTConst;
129 }
130
cast(TBasicType newType,const TConstantUnion & constant)131 bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant)
132 {
133 switch (newType)
134 {
135 case EbtFloat:
136 switch (constant.type)
137 {
138 case EbtInt:
139 setFConst(static_cast<float>(constant.getIConst()));
140 break;
141 case EbtUInt:
142 setFConst(static_cast<float>(constant.getUConst()));
143 break;
144 case EbtBool:
145 setFConst(static_cast<float>(constant.getBConst()));
146 break;
147 case EbtFloat:
148 setFConst(static_cast<float>(constant.getFConst()));
149 break;
150 default:
151 return false;
152 }
153 break;
154 case EbtInt:
155 switch (constant.type)
156 {
157 case EbtInt:
158 setIConst(static_cast<int>(constant.getIConst()));
159 break;
160 case EbtUInt:
161 setIConst(static_cast<int>(constant.getUConst()));
162 break;
163 case EbtBool:
164 setIConst(static_cast<int>(constant.getBConst()));
165 break;
166 case EbtFloat:
167 setIConst(static_cast<int>(constant.getFConst()));
168 break;
169 default:
170 return false;
171 }
172 break;
173 case EbtUInt:
174 switch (constant.type)
175 {
176 case EbtInt:
177 setUConst(static_cast<unsigned int>(constant.getIConst()));
178 break;
179 case EbtUInt:
180 setUConst(static_cast<unsigned int>(constant.getUConst()));
181 break;
182 case EbtBool:
183 setUConst(static_cast<unsigned int>(constant.getBConst()));
184 break;
185 case EbtFloat:
186 if (constant.getFConst() < 0.0f)
187 {
188 // Avoid undefined behavior in C++ by first casting to signed int.
189 setUConst(
190 static_cast<unsigned int>(static_cast<int>(constant.getFConst())));
191 }
192 else
193 {
194 setUConst(static_cast<unsigned int>(constant.getFConst()));
195 }
196 break;
197 default:
198 return false;
199 }
200 break;
201 case EbtBool:
202 switch (constant.type)
203 {
204 case EbtInt:
205 setBConst(constant.getIConst() != 0);
206 break;
207 case EbtUInt:
208 setBConst(constant.getUConst() != 0);
209 break;
210 case EbtBool:
211 setBConst(constant.getBConst());
212 break;
213 case EbtFloat:
214 setBConst(constant.getFConst() != 0.0f);
215 break;
216 default:
217 return false;
218 }
219 break;
220 case EbtStruct: // Struct fields don't get cast
221 switch (constant.type)
222 {
223 case EbtInt:
224 setIConst(constant.getIConst());
225 break;
226 case EbtUInt:
227 setUConst(constant.getUConst());
228 break;
229 case EbtBool:
230 setBConst(constant.getBConst());
231 break;
232 case EbtFloat:
233 setFConst(constant.getFConst());
234 break;
235 default:
236 return false;
237 }
238 break;
239 default:
240 return false;
241 }
242
243 return true;
244 }
245
operator ==(const int i) const246 bool TConstantUnion::operator==(const int i) const
247 {
248 switch (type)
249 {
250 case EbtFloat:
251 return static_cast<float>(i) == fConst;
252 default:
253 return i == iConst;
254 }
255 }
256
operator ==(const unsigned int u) const257 bool TConstantUnion::operator==(const unsigned int u) const
258 {
259 switch (type)
260 {
261 case EbtFloat:
262 return static_cast<float>(u) == fConst;
263 default:
264 return u == uConst;
265 }
266 }
267
operator ==(const float f) const268 bool TConstantUnion::operator==(const float f) const
269 {
270 switch (type)
271 {
272 case EbtInt:
273 return f == static_cast<float>(iConst);
274 case EbtUInt:
275 return f == static_cast<float>(uConst);
276 default:
277 return f == fConst;
278 }
279 }
280
operator ==(const bool b) const281 bool TConstantUnion::operator==(const bool b) const
282 {
283 return b == bConst;
284 }
285
operator ==(const TYuvCscStandardEXT s) const286 bool TConstantUnion::operator==(const TYuvCscStandardEXT s) const
287 {
288 return s == yuvCscStandardEXTConst;
289 }
290
operator ==(const TConstantUnion & constant) const291 bool TConstantUnion::operator==(const TConstantUnion &constant) const
292 {
293 ImplicitTypeConversion conversion = GetConversion(constant.type, type);
294 if (conversion == ImplicitTypeConversion::Same)
295 {
296 switch (type)
297 {
298 case EbtInt:
299 return constant.iConst == iConst;
300 case EbtUInt:
301 return constant.uConst == uConst;
302 case EbtFloat:
303 return constant.fConst == fConst;
304 case EbtBool:
305 return constant.bConst == bConst;
306 case EbtYuvCscStandardEXT:
307 return constant.yuvCscStandardEXTConst == yuvCscStandardEXTConst;
308 default:
309 return false;
310 }
311 }
312 else if (conversion == ImplicitTypeConversion::Invalid)
313 {
314 return false;
315 }
316 else
317 {
318 return constant.getFConst() == getFConst();
319 }
320 }
321
operator !=(const int i) const322 bool TConstantUnion::operator!=(const int i) const
323 {
324 return !operator==(i);
325 }
326
operator !=(const unsigned int u) const327 bool TConstantUnion::operator!=(const unsigned int u) const
328 {
329 return !operator==(u);
330 }
331
operator !=(const float f) const332 bool TConstantUnion::operator!=(const float f) const
333 {
334 return !operator==(f);
335 }
336
operator !=(const bool b) const337 bool TConstantUnion::operator!=(const bool b) const
338 {
339 return !operator==(b);
340 }
341
operator !=(const TYuvCscStandardEXT s) const342 bool TConstantUnion::operator!=(const TYuvCscStandardEXT s) const
343 {
344 return !operator==(s);
345 }
346
operator !=(const TConstantUnion & constant) const347 bool TConstantUnion::operator!=(const TConstantUnion &constant) const
348 {
349 return !operator==(constant);
350 }
351
operator >(const TConstantUnion & constant) const352 bool TConstantUnion::operator>(const TConstantUnion &constant) const
353 {
354
355 ImplicitTypeConversion conversion = GetConversion(constant.type, type);
356 if (conversion == ImplicitTypeConversion::Same)
357 {
358 switch (type)
359 {
360 case EbtInt:
361 return iConst > constant.iConst;
362 case EbtUInt:
363 return uConst > constant.uConst;
364 case EbtFloat:
365 return fConst > constant.fConst;
366 default:
367 return false; // Invalid operation, handled at semantic analysis
368 }
369 }
370 else
371 {
372 ASSERT(conversion != ImplicitTypeConversion::Invalid);
373 return getFConst() > constant.getFConst();
374 }
375 }
376
operator <(const TConstantUnion & constant) const377 bool TConstantUnion::operator<(const TConstantUnion &constant) const
378 {
379 ImplicitTypeConversion conversion = GetConversion(constant.type, type);
380 if (conversion == ImplicitTypeConversion::Same)
381 {
382 switch (type)
383 {
384 case EbtInt:
385 return iConst < constant.iConst;
386 case EbtUInt:
387 return uConst < constant.uConst;
388 case EbtFloat:
389 return fConst < constant.fConst;
390 default:
391 return false; // Invalid operation, handled at semantic analysis
392 }
393 }
394 else
395 {
396 ASSERT(conversion != ImplicitTypeConversion::Invalid);
397 return getFConst() < constant.getFConst();
398 }
399 }
400
401 // static
add(const TConstantUnion & lhs,const TConstantUnion & rhs,TDiagnostics * diag,const TSourceLoc & line)402 TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,
403 const TConstantUnion &rhs,
404 TDiagnostics *diag,
405 const TSourceLoc &line)
406 {
407 TConstantUnion returnValue;
408
409 ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);
410 if (conversion == ImplicitTypeConversion::Same)
411 {
412 switch (lhs.type)
413 {
414 case EbtInt:
415 returnValue.setIConst(gl::WrappingSum<int>(lhs.iConst, rhs.iConst));
416 break;
417 case EbtUInt:
418 returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst));
419 break;
420 case EbtFloat:
421 returnValue.setFConst(CheckedSum(lhs.fConst, rhs.fConst, diag, line));
422 break;
423 default:
424 UNREACHABLE();
425 }
426 }
427 else
428 {
429 ASSERT(conversion != ImplicitTypeConversion::Invalid);
430 returnValue.setFConst(CheckedSum(lhs.getFConst(), rhs.getFConst(), diag, line));
431 }
432
433 return returnValue;
434 }
435
436 // static
sub(const TConstantUnion & lhs,const TConstantUnion & rhs,TDiagnostics * diag,const TSourceLoc & line)437 TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
438 const TConstantUnion &rhs,
439 TDiagnostics *diag,
440 const TSourceLoc &line)
441 {
442 TConstantUnion returnValue;
443
444 ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);
445 if (conversion == ImplicitTypeConversion::Same)
446 {
447 switch (lhs.type)
448 {
449 case EbtInt:
450 returnValue.setIConst(gl::WrappingDiff<int>(lhs.iConst, rhs.iConst));
451 break;
452 case EbtUInt:
453 returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst));
454 break;
455 case EbtFloat:
456 returnValue.setFConst(CheckedDiff(lhs.fConst, rhs.fConst, diag, line));
457 break;
458 default:
459 UNREACHABLE();
460 }
461 }
462 else
463 {
464 ASSERT(conversion != ImplicitTypeConversion::Invalid);
465 returnValue.setFConst(CheckedDiff(lhs.getFConst(), rhs.getFConst(), diag, line));
466 }
467
468 return returnValue;
469 }
470
471 // static
mul(const TConstantUnion & lhs,const TConstantUnion & rhs,TDiagnostics * diag,const TSourceLoc & line)472 TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
473 const TConstantUnion &rhs,
474 TDiagnostics *diag,
475 const TSourceLoc &line)
476 {
477 TConstantUnion returnValue;
478
479 ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);
480 if (conversion == ImplicitTypeConversion::Same)
481 {
482 switch (lhs.type)
483 {
484 case EbtInt:
485 returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst));
486 break;
487 case EbtUInt:
488 // Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely
489 // on that to implement wrapping multiplication.
490 returnValue.setUConst(lhs.uConst * rhs.uConst);
491 break;
492 case EbtFloat:
493 returnValue.setFConst(CheckedMul(lhs.fConst, rhs.fConst, diag, line));
494 break;
495 default:
496 UNREACHABLE();
497 }
498 }
499 else
500 {
501 ASSERT(conversion != ImplicitTypeConversion::Invalid);
502 returnValue.setFConst(CheckedMul(lhs.getFConst(), rhs.getFConst(), diag, line));
503 }
504
505 return returnValue;
506 }
507
operator %(const TConstantUnion & constant) const508 TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const
509 {
510 TConstantUnion returnValue;
511 ASSERT(type == constant.type);
512 switch (type)
513 {
514 case EbtInt:
515 returnValue.setIConst(iConst % constant.iConst);
516 break;
517 case EbtUInt:
518 returnValue.setUConst(uConst % constant.uConst);
519 break;
520 default:
521 UNREACHABLE();
522 }
523
524 return returnValue;
525 }
526
527 // static
rshift(const TConstantUnion & lhs,const TConstantUnion & rhs,TDiagnostics * diag,const TSourceLoc & line)528 TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs,
529 const TConstantUnion &rhs,
530 TDiagnostics *diag,
531 const TSourceLoc &line)
532 {
533 TConstantUnion returnValue;
534 ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
535 ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
536 if (!IsValidShiftOffset(rhs))
537 {
538 diag->warning(line, "Undefined shift (operand out of range)", ">>");
539 switch (lhs.type)
540 {
541 case EbtInt:
542 returnValue.setIConst(0);
543 break;
544 case EbtUInt:
545 returnValue.setUConst(0u);
546 break;
547 default:
548 UNREACHABLE();
549 }
550 return returnValue;
551 }
552
553 switch (lhs.type)
554 {
555 case EbtInt:
556 {
557 unsigned int shiftOffset = 0;
558 switch (rhs.type)
559 {
560 case EbtInt:
561 shiftOffset = static_cast<unsigned int>(rhs.iConst);
562 break;
563 case EbtUInt:
564 shiftOffset = rhs.uConst;
565 break;
566 default:
567 UNREACHABLE();
568 }
569 if (shiftOffset > 0)
570 {
571 // ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend
572 // the sign bit." In C++ shifting negative integers is undefined, so we implement
573 // extending the sign bit manually.
574 int lhsSafe = lhs.iConst;
575 if (lhsSafe == std::numeric_limits<int>::min())
576 {
577 // The min integer needs special treatment because only bit it has set is the
578 // sign bit, which we clear later to implement safe right shift of negative
579 // numbers.
580 lhsSafe = -0x40000000;
581 --shiftOffset;
582 }
583 if (shiftOffset > 0)
584 {
585 bool extendSignBit = false;
586 if (lhsSafe < 0)
587 {
588 extendSignBit = true;
589 // Clear the sign bit so that bitshift right is defined in C++.
590 lhsSafe &= 0x7fffffff;
591 ASSERT(lhsSafe > 0);
592 }
593 returnValue.setIConst(lhsSafe >> shiftOffset);
594
595 // Manually fill in the extended sign bit if necessary.
596 if (extendSignBit)
597 {
598 int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset));
599 returnValue.setIConst(returnValue.getIConst() | extendedSignBit);
600 }
601 }
602 else
603 {
604 returnValue.setIConst(lhsSafe);
605 }
606 }
607 else
608 {
609 returnValue.setIConst(lhs.iConst);
610 }
611 break;
612 }
613 case EbtUInt:
614 switch (rhs.type)
615 {
616 case EbtInt:
617 returnValue.setUConst(lhs.uConst >> rhs.iConst);
618 break;
619 case EbtUInt:
620 returnValue.setUConst(lhs.uConst >> rhs.uConst);
621 break;
622 default:
623 UNREACHABLE();
624 }
625 break;
626
627 default:
628 UNREACHABLE();
629 }
630 return returnValue;
631 }
632
633 // static
lshift(const TConstantUnion & lhs,const TConstantUnion & rhs,TDiagnostics * diag,const TSourceLoc & line)634 TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,
635 const TConstantUnion &rhs,
636 TDiagnostics *diag,
637 const TSourceLoc &line)
638 {
639 TConstantUnion returnValue;
640 ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
641 ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
642 if (!IsValidShiftOffset(rhs))
643 {
644 diag->warning(line, "Undefined shift (operand out of range)", "<<");
645 switch (lhs.type)
646 {
647 case EbtInt:
648 returnValue.setIConst(0);
649 break;
650 case EbtUInt:
651 returnValue.setUConst(0u);
652 break;
653 default:
654 UNREACHABLE();
655 }
656 return returnValue;
657 }
658
659 switch (lhs.type)
660 {
661 case EbtInt:
662 switch (rhs.type)
663 {
664 // Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that
665 // lhs is "interpreted as a bit pattern". This also avoids the possibility of signed
666 // integer overflow or undefined shift of a negative integer.
667 case EbtInt:
668 returnValue.setIConst(
669 static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.iConst));
670 break;
671 case EbtUInt:
672 returnValue.setIConst(
673 static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.uConst));
674 break;
675 default:
676 UNREACHABLE();
677 }
678 break;
679
680 case EbtUInt:
681 switch (rhs.type)
682 {
683 case EbtInt:
684 returnValue.setUConst(lhs.uConst << rhs.iConst);
685 break;
686 case EbtUInt:
687 returnValue.setUConst(lhs.uConst << rhs.uConst);
688 break;
689 default:
690 UNREACHABLE();
691 }
692 break;
693
694 default:
695 UNREACHABLE();
696 }
697 return returnValue;
698 }
699
operator &(const TConstantUnion & constant) const700 TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
701 {
702 TConstantUnion returnValue;
703 ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
704 switch (type)
705 {
706 case EbtInt:
707 returnValue.setIConst(iConst & constant.iConst);
708 break;
709 case EbtUInt:
710 returnValue.setUConst(uConst & constant.uConst);
711 break;
712 default:
713 UNREACHABLE();
714 }
715
716 return returnValue;
717 }
718
operator |(const TConstantUnion & constant) const719 TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
720 {
721 TConstantUnion returnValue;
722 ASSERT(type == constant.type);
723 switch (type)
724 {
725 case EbtInt:
726 returnValue.setIConst(iConst | constant.iConst);
727 break;
728 case EbtUInt:
729 returnValue.setUConst(uConst | constant.uConst);
730 break;
731 default:
732 UNREACHABLE();
733 }
734
735 return returnValue;
736 }
737
operator ^(const TConstantUnion & constant) const738 TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
739 {
740 TConstantUnion returnValue;
741 ASSERT(type == constant.type);
742 switch (type)
743 {
744 case EbtInt:
745 returnValue.setIConst(iConst ^ constant.iConst);
746 break;
747 case EbtUInt:
748 returnValue.setUConst(uConst ^ constant.uConst);
749 break;
750 default:
751 UNREACHABLE();
752 }
753
754 return returnValue;
755 }
756
operator &&(const TConstantUnion & constant) const757 TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
758 {
759 TConstantUnion returnValue;
760 ASSERT(type == constant.type);
761 switch (type)
762 {
763 case EbtBool:
764 returnValue.setBConst(bConst && constant.bConst);
765 break;
766 default:
767 UNREACHABLE();
768 }
769
770 return returnValue;
771 }
772
operator ||(const TConstantUnion & constant) const773 TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
774 {
775 TConstantUnion returnValue;
776 ASSERT(type == constant.type);
777 switch (type)
778 {
779 case EbtBool:
780 returnValue.setBConst(bConst || constant.bConst);
781 break;
782 default:
783 UNREACHABLE();
784 }
785
786 return returnValue;
787 }
788
789 } // namespace sh
790