• 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         case EbtYuvCscStandardEXT:
244             switch (constant.type)
245             {
246                 case EbtYuvCscStandardEXT:
247                     setYuvCscStandardEXTConst(constant.getYuvCscStandardEXTConst());
248                     break;
249                 default:
250                     return false;
251             }
252             break;
253         default:
254             return false;
255     }
256 
257     return true;
258 }
259 
operator ==(const int i) const260 bool TConstantUnion::operator==(const int i) const
261 {
262     switch (type)
263     {
264         case EbtFloat:
265             return static_cast<float>(i) == fConst;
266         default:
267             return i == iConst;
268     }
269 }
270 
operator ==(const unsigned int u) const271 bool TConstantUnion::operator==(const unsigned int u) const
272 {
273     switch (type)
274     {
275         case EbtFloat:
276             return static_cast<float>(u) == fConst;
277         default:
278             return u == uConst;
279     }
280 }
281 
operator ==(const float f) const282 bool TConstantUnion::operator==(const float f) const
283 {
284     switch (type)
285     {
286         case EbtInt:
287             return f == static_cast<float>(iConst);
288         case EbtUInt:
289             return f == static_cast<float>(uConst);
290         default:
291             return f == fConst;
292     }
293 }
294 
operator ==(const bool b) const295 bool TConstantUnion::operator==(const bool b) const
296 {
297     return b == bConst;
298 }
299 
operator ==(const TYuvCscStandardEXT s) const300 bool TConstantUnion::operator==(const TYuvCscStandardEXT s) const
301 {
302     return s == yuvCscStandardEXTConst;
303 }
304 
operator ==(const TConstantUnion & constant) const305 bool TConstantUnion::operator==(const TConstantUnion &constant) const
306 {
307     ImplicitTypeConversion conversion = GetConversion(constant.type, type);
308     if (conversion == ImplicitTypeConversion::Same)
309     {
310         switch (type)
311         {
312             case EbtInt:
313                 return constant.iConst == iConst;
314             case EbtUInt:
315                 return constant.uConst == uConst;
316             case EbtFloat:
317                 return constant.fConst == fConst;
318             case EbtBool:
319                 return constant.bConst == bConst;
320             case EbtYuvCscStandardEXT:
321                 return constant.yuvCscStandardEXTConst == yuvCscStandardEXTConst;
322             default:
323                 return false;
324         }
325     }
326     else if (conversion == ImplicitTypeConversion::Invalid)
327     {
328         return false;
329     }
330     else
331     {
332         return constant.getFConst() == getFConst();
333     }
334 }
335 
operator !=(const int i) const336 bool TConstantUnion::operator!=(const int i) const
337 {
338     return !operator==(i);
339 }
340 
operator !=(const unsigned int u) const341 bool TConstantUnion::operator!=(const unsigned int u) const
342 {
343     return !operator==(u);
344 }
345 
operator !=(const float f) const346 bool TConstantUnion::operator!=(const float f) const
347 {
348     return !operator==(f);
349 }
350 
operator !=(const bool b) const351 bool TConstantUnion::operator!=(const bool b) const
352 {
353     return !operator==(b);
354 }
355 
operator !=(const TYuvCscStandardEXT s) const356 bool TConstantUnion::operator!=(const TYuvCscStandardEXT s) const
357 {
358     return !operator==(s);
359 }
360 
operator !=(const TConstantUnion & constant) const361 bool TConstantUnion::operator!=(const TConstantUnion &constant) const
362 {
363     return !operator==(constant);
364 }
365 
operator >(const TConstantUnion & constant) const366 bool TConstantUnion::operator>(const TConstantUnion &constant) const
367 {
368 
369     ImplicitTypeConversion conversion = GetConversion(constant.type, type);
370     if (conversion == ImplicitTypeConversion::Same)
371     {
372         switch (type)
373         {
374             case EbtInt:
375                 return iConst > constant.iConst;
376             case EbtUInt:
377                 return uConst > constant.uConst;
378             case EbtFloat:
379                 return fConst > constant.fConst;
380             default:
381                 return false;  // Invalid operation, handled at semantic analysis
382         }
383     }
384     else
385     {
386         ASSERT(conversion != ImplicitTypeConversion::Invalid);
387         return getFConst() > constant.getFConst();
388     }
389 }
390 
operator <(const TConstantUnion & constant) const391 bool TConstantUnion::operator<(const TConstantUnion &constant) const
392 {
393     ImplicitTypeConversion conversion = GetConversion(constant.type, type);
394     if (conversion == ImplicitTypeConversion::Same)
395     {
396         switch (type)
397         {
398             case EbtInt:
399                 return iConst < constant.iConst;
400             case EbtUInt:
401                 return uConst < constant.uConst;
402             case EbtFloat:
403                 return fConst < constant.fConst;
404             default:
405                 return false;  // Invalid operation, handled at semantic analysis
406         }
407     }
408     else
409     {
410         ASSERT(conversion != ImplicitTypeConversion::Invalid);
411         return getFConst() < constant.getFConst();
412     }
413 }
414 
415 // static
add(const TConstantUnion & lhs,const TConstantUnion & rhs,TDiagnostics * diag,const TSourceLoc & line)416 TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,
417                                    const TConstantUnion &rhs,
418                                    TDiagnostics *diag,
419                                    const TSourceLoc &line)
420 {
421     TConstantUnion returnValue;
422 
423     ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);
424     if (conversion == ImplicitTypeConversion::Same)
425     {
426         switch (lhs.type)
427         {
428             case EbtInt:
429                 returnValue.setIConst(gl::WrappingSum<int>(lhs.iConst, rhs.iConst));
430                 break;
431             case EbtUInt:
432                 returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst));
433                 break;
434             case EbtFloat:
435                 returnValue.setFConst(CheckedSum(lhs.fConst, rhs.fConst, diag, line));
436                 break;
437             default:
438                 UNREACHABLE();
439         }
440     }
441     else
442     {
443         ASSERT(conversion != ImplicitTypeConversion::Invalid);
444         returnValue.setFConst(CheckedSum(lhs.getFConst(), rhs.getFConst(), diag, line));
445     }
446 
447     return returnValue;
448 }
449 
450 // static
sub(const TConstantUnion & lhs,const TConstantUnion & rhs,TDiagnostics * diag,const TSourceLoc & line)451 TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
452                                    const TConstantUnion &rhs,
453                                    TDiagnostics *diag,
454                                    const TSourceLoc &line)
455 {
456     TConstantUnion returnValue;
457 
458     ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);
459     if (conversion == ImplicitTypeConversion::Same)
460     {
461         switch (lhs.type)
462         {
463             case EbtInt:
464                 returnValue.setIConst(gl::WrappingDiff<int>(lhs.iConst, rhs.iConst));
465                 break;
466             case EbtUInt:
467                 returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst));
468                 break;
469             case EbtFloat:
470                 returnValue.setFConst(CheckedDiff(lhs.fConst, rhs.fConst, diag, line));
471                 break;
472             default:
473                 UNREACHABLE();
474         }
475     }
476     else
477     {
478         ASSERT(conversion != ImplicitTypeConversion::Invalid);
479         returnValue.setFConst(CheckedDiff(lhs.getFConst(), rhs.getFConst(), diag, line));
480     }
481 
482     return returnValue;
483 }
484 
485 // static
mul(const TConstantUnion & lhs,const TConstantUnion & rhs,TDiagnostics * diag,const TSourceLoc & line)486 TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
487                                    const TConstantUnion &rhs,
488                                    TDiagnostics *diag,
489                                    const TSourceLoc &line)
490 {
491     TConstantUnion returnValue;
492 
493     ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);
494     if (conversion == ImplicitTypeConversion::Same)
495     {
496         switch (lhs.type)
497         {
498             case EbtInt:
499                 returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst));
500                 break;
501             case EbtUInt:
502                 // Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely
503                 // on that to implement wrapping multiplication.
504                 returnValue.setUConst(lhs.uConst * rhs.uConst);
505                 break;
506             case EbtFloat:
507                 returnValue.setFConst(CheckedMul(lhs.fConst, rhs.fConst, diag, line));
508                 break;
509             default:
510                 UNREACHABLE();
511         }
512     }
513     else
514     {
515         ASSERT(conversion != ImplicitTypeConversion::Invalid);
516         returnValue.setFConst(CheckedMul(lhs.getFConst(), rhs.getFConst(), diag, line));
517     }
518 
519     return returnValue;
520 }
521 
operator %(const TConstantUnion & constant) const522 TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const
523 {
524     TConstantUnion returnValue;
525     ASSERT(type == constant.type);
526     switch (type)
527     {
528         case EbtInt:
529             returnValue.setIConst(iConst % constant.iConst);
530             break;
531         case EbtUInt:
532             returnValue.setUConst(uConst % constant.uConst);
533             break;
534         default:
535             UNREACHABLE();
536     }
537 
538     return returnValue;
539 }
540 
541 // static
rshift(const TConstantUnion & lhs,const TConstantUnion & rhs,TDiagnostics * diag,const TSourceLoc & line)542 TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs,
543                                       const TConstantUnion &rhs,
544                                       TDiagnostics *diag,
545                                       const TSourceLoc &line)
546 {
547     TConstantUnion returnValue;
548     ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
549     ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
550     if (!IsValidShiftOffset(rhs))
551     {
552         diag->warning(line, "Undefined shift (operand out of range)", ">>");
553         switch (lhs.type)
554         {
555             case EbtInt:
556                 returnValue.setIConst(0);
557                 break;
558             case EbtUInt:
559                 returnValue.setUConst(0u);
560                 break;
561             default:
562                 UNREACHABLE();
563         }
564         return returnValue;
565     }
566 
567     switch (lhs.type)
568     {
569         case EbtInt:
570         {
571             unsigned int shiftOffset = 0;
572             switch (rhs.type)
573             {
574                 case EbtInt:
575                     shiftOffset = static_cast<unsigned int>(rhs.iConst);
576                     break;
577                 case EbtUInt:
578                     shiftOffset = rhs.uConst;
579                     break;
580                 default:
581                     UNREACHABLE();
582             }
583             if (shiftOffset > 0)
584             {
585                 // ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend
586                 // the sign bit." In C++ shifting negative integers is undefined, so we implement
587                 // extending the sign bit manually.
588                 int lhsSafe = lhs.iConst;
589                 if (lhsSafe == std::numeric_limits<int>::min())
590                 {
591                     // The min integer needs special treatment because only bit it has set is the
592                     // sign bit, which we clear later to implement safe right shift of negative
593                     // numbers.
594                     lhsSafe = -0x40000000;
595                     --shiftOffset;
596                 }
597                 if (shiftOffset > 0)
598                 {
599                     bool extendSignBit = false;
600                     if (lhsSafe < 0)
601                     {
602                         extendSignBit = true;
603                         // Clear the sign bit so that bitshift right is defined in C++.
604                         lhsSafe &= 0x7fffffff;
605                         ASSERT(lhsSafe > 0);
606                     }
607                     returnValue.setIConst(lhsSafe >> shiftOffset);
608 
609                     // Manually fill in the extended sign bit if necessary.
610                     if (extendSignBit)
611                     {
612                         int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset));
613                         returnValue.setIConst(returnValue.getIConst() | extendedSignBit);
614                     }
615                 }
616                 else
617                 {
618                     returnValue.setIConst(lhsSafe);
619                 }
620             }
621             else
622             {
623                 returnValue.setIConst(lhs.iConst);
624             }
625             break;
626         }
627         case EbtUInt:
628             switch (rhs.type)
629             {
630                 case EbtInt:
631                     returnValue.setUConst(lhs.uConst >> rhs.iConst);
632                     break;
633                 case EbtUInt:
634                     returnValue.setUConst(lhs.uConst >> rhs.uConst);
635                     break;
636                 default:
637                     UNREACHABLE();
638             }
639             break;
640 
641         default:
642             UNREACHABLE();
643     }
644     return returnValue;
645 }
646 
647 // static
lshift(const TConstantUnion & lhs,const TConstantUnion & rhs,TDiagnostics * diag,const TSourceLoc & line)648 TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,
649                                       const TConstantUnion &rhs,
650                                       TDiagnostics *diag,
651                                       const TSourceLoc &line)
652 {
653     TConstantUnion returnValue;
654     ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
655     ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
656     if (!IsValidShiftOffset(rhs))
657     {
658         diag->warning(line, "Undefined shift (operand out of range)", "<<");
659         switch (lhs.type)
660         {
661             case EbtInt:
662                 returnValue.setIConst(0);
663                 break;
664             case EbtUInt:
665                 returnValue.setUConst(0u);
666                 break;
667             default:
668                 UNREACHABLE();
669         }
670         return returnValue;
671     }
672 
673     switch (lhs.type)
674     {
675         case EbtInt:
676             switch (rhs.type)
677             {
678                 // Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that
679                 // lhs is "interpreted as a bit pattern". This also avoids the possibility of signed
680                 // integer overflow or undefined shift of a negative integer.
681                 case EbtInt:
682                     returnValue.setIConst(
683                         static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.iConst));
684                     break;
685                 case EbtUInt:
686                     returnValue.setIConst(
687                         static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.uConst));
688                     break;
689                 default:
690                     UNREACHABLE();
691             }
692             break;
693 
694         case EbtUInt:
695             switch (rhs.type)
696             {
697                 case EbtInt:
698                     returnValue.setUConst(lhs.uConst << rhs.iConst);
699                     break;
700                 case EbtUInt:
701                     returnValue.setUConst(lhs.uConst << rhs.uConst);
702                     break;
703                 default:
704                     UNREACHABLE();
705             }
706             break;
707 
708         default:
709             UNREACHABLE();
710     }
711     return returnValue;
712 }
713 
operator &(const TConstantUnion & constant) const714 TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
715 {
716     TConstantUnion returnValue;
717     ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
718     switch (type)
719     {
720         case EbtInt:
721             returnValue.setIConst(iConst & constant.iConst);
722             break;
723         case EbtUInt:
724             returnValue.setUConst(uConst & constant.uConst);
725             break;
726         default:
727             UNREACHABLE();
728     }
729 
730     return returnValue;
731 }
732 
operator |(const TConstantUnion & constant) const733 TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
734 {
735     TConstantUnion returnValue;
736     ASSERT(type == constant.type);
737     switch (type)
738     {
739         case EbtInt:
740             returnValue.setIConst(iConst | constant.iConst);
741             break;
742         case EbtUInt:
743             returnValue.setUConst(uConst | constant.uConst);
744             break;
745         default:
746             UNREACHABLE();
747     }
748 
749     return returnValue;
750 }
751 
operator ^(const TConstantUnion & constant) const752 TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
753 {
754     TConstantUnion returnValue;
755     ASSERT(type == constant.type);
756     switch (type)
757     {
758         case EbtInt:
759             returnValue.setIConst(iConst ^ constant.iConst);
760             break;
761         case EbtUInt:
762             returnValue.setUConst(uConst ^ constant.uConst);
763             break;
764         default:
765             UNREACHABLE();
766     }
767 
768     return returnValue;
769 }
770 
operator &&(const TConstantUnion & constant) const771 TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
772 {
773     TConstantUnion returnValue;
774     ASSERT(type == constant.type);
775     switch (type)
776     {
777         case EbtBool:
778             returnValue.setBConst(bConst && constant.bConst);
779             break;
780         default:
781             UNREACHABLE();
782     }
783 
784     return returnValue;
785 }
786 
operator ||(const TConstantUnion & constant) const787 TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
788 {
789     TConstantUnion returnValue;
790     ASSERT(type == constant.type);
791     switch (type)
792     {
793         case EbtBool:
794             returnValue.setBConst(bConst || constant.bConst);
795             break;
796         default:
797             UNREACHABLE();
798     }
799 
800     return returnValue;
801 }
802 
803 }  // namespace sh
804