• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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