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