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