Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/src/compiler/translator/ConstantUnion.cpp
1693 views
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
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
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
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
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
70
TConstantUnion::TConstantUnion() : iConst(0), type(EbtVoid) {}
71
72
TConstantUnion::TConstantUnion(int i) : iConst(i), type(EbtInt) {}
73
74
TConstantUnion::TConstantUnion(unsigned int u) : uConst(u), type(EbtUInt) {}
75
76
TConstantUnion::TConstantUnion(float f) : fConst(f), type(EbtFloat) {}
77
78
TConstantUnion::TConstantUnion(bool b) : bConst(b), type(EbtBool) {}
79
80
int TConstantUnion::getIConst() const
81
{
82
ASSERT(type == EbtInt);
83
return iConst;
84
}
85
86
unsigned int TConstantUnion::getUConst() const
87
{
88
ASSERT(type == EbtUInt);
89
return uConst;
90
}
91
92
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
106
bool TConstantUnion::getBConst() const
107
{
108
ASSERT(type == EbtBool);
109
return bConst;
110
}
111
112
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
129
TYuvCscStandardEXT TConstantUnion::getYuvCscStandardEXTConst() const
130
{
131
ASSERT(type == EbtYuvCscStandardEXT);
132
return yuvCscStandardEXTConst;
133
}
134
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
250
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
261
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
272
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
285
bool TConstantUnion::operator==(const bool b) const
286
{
287
return b == bConst;
288
}
289
290
bool TConstantUnion::operator==(const TYuvCscStandardEXT s) const
291
{
292
return s == yuvCscStandardEXTConst;
293
}
294
295
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
326
bool TConstantUnion::operator!=(const int i) const
327
{
328
return !operator==(i);
329
}
330
331
bool TConstantUnion::operator!=(const unsigned int u) const
332
{
333
return !operator==(u);
334
}
335
336
bool TConstantUnion::operator!=(const float f) const
337
{
338
return !operator==(f);
339
}
340
341
bool TConstantUnion::operator!=(const bool b) const
342
{
343
return !operator==(b);
344
}
345
346
bool TConstantUnion::operator!=(const TYuvCscStandardEXT s) const
347
{
348
return !operator==(s);
349
}
350
351
bool TConstantUnion::operator!=(const TConstantUnion &constant) const
352
{
353
return !operator==(constant);
354
}
355
356
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
381
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
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
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
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
512
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
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
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
704
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
723
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
742
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
761
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
777
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
795