blob: b4074bf77d0c529fd21fefe75013cbcfac5e34d8 [file] [log] [blame]
Jamie Madill47cb73a2016-09-09 11:41:44 -04001//
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
Jamie Madill5db69f52016-09-15 12:47:32 -040010#include "base/numerics/safe_math.h"
Olli Etuaho7f9a55f2016-10-03 14:32:08 +010011#include "common/mathutil.h"
Jamie Madill47cb73a2016-09-09 11:41:44 -040012#include "compiler/translator/Diagnostics.h"
13
Jamie Madill5db69f52016-09-15 12:47:32 -040014namespace
15{
16
17template <typename T>
18T CheckedSum(base::CheckedNumeric<T> lhs,
19 base::CheckedNumeric<T> rhs,
20 TDiagnostics *diag,
21 const TSourceLoc &line)
22{
23 ASSERT(lhs.IsValid() && rhs.IsValid());
24 auto result = lhs + rhs;
25 if (!result.IsValid())
26 {
27 diag->error(line, "Addition out of range", "*", "");
28 return 0;
29 }
30 return result.ValueOrDefault(0);
31}
32
33template <typename T>
34T CheckedDiff(base::CheckedNumeric<T> lhs,
35 base::CheckedNumeric<T> rhs,
36 TDiagnostics *diag,
37 const TSourceLoc &line)
38{
39 ASSERT(lhs.IsValid() && rhs.IsValid());
40 auto result = lhs - rhs;
41 if (!result.IsValid())
42 {
43 diag->error(line, "Difference out of range", "*", "");
44 return 0;
45 }
46 return result.ValueOrDefault(0);
47}
48
49template <typename T>
50T CheckedMul(base::CheckedNumeric<T> lhs,
51 base::CheckedNumeric<T> rhs,
52 TDiagnostics *diag,
53 const TSourceLoc &line)
54{
55 ASSERT(lhs.IsValid() && rhs.IsValid());
56 auto result = lhs * rhs;
57 if (!result.IsValid())
58 {
59 diag->error(line, "Multiplication out of range", "*", "");
60 return 0;
61 }
62 return result.ValueOrDefault(0);
63}
64
65} // anonymous namespace
66
Jamie Madill47cb73a2016-09-09 11:41:44 -040067TConstantUnion::TConstantUnion()
68{
69 iConst = 0;
70 type = EbtVoid;
71}
72
73bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant)
74{
75 switch (newType)
76 {
77 case EbtFloat:
78 switch (constant.type)
79 {
80 case EbtInt:
81 setFConst(static_cast<float>(constant.getIConst()));
82 break;
83 case EbtUInt:
84 setFConst(static_cast<float>(constant.getUConst()));
85 break;
86 case EbtBool:
87 setFConst(static_cast<float>(constant.getBConst()));
88 break;
89 case EbtFloat:
90 setFConst(static_cast<float>(constant.getFConst()));
91 break;
92 default:
93 return false;
94 }
95 break;
96 case EbtInt:
97 switch (constant.type)
98 {
99 case EbtInt:
100 setIConst(static_cast<int>(constant.getIConst()));
101 break;
102 case EbtUInt:
103 setIConst(static_cast<int>(constant.getUConst()));
104 break;
105 case EbtBool:
106 setIConst(static_cast<int>(constant.getBConst()));
107 break;
108 case EbtFloat:
109 setIConst(static_cast<int>(constant.getFConst()));
110 break;
111 default:
112 return false;
113 }
114 break;
115 case EbtUInt:
116 switch (constant.type)
117 {
118 case EbtInt:
119 setUConst(static_cast<unsigned int>(constant.getIConst()));
120 break;
121 case EbtUInt:
122 setUConst(static_cast<unsigned int>(constant.getUConst()));
123 break;
124 case EbtBool:
125 setUConst(static_cast<unsigned int>(constant.getBConst()));
126 break;
127 case EbtFloat:
128 setUConst(static_cast<unsigned int>(constant.getFConst()));
129 break;
130 default:
131 return false;
132 }
133 break;
134 case EbtBool:
135 switch (constant.type)
136 {
137 case EbtInt:
138 setBConst(constant.getIConst() != 0);
139 break;
140 case EbtUInt:
141 setBConst(constant.getUConst() != 0);
142 break;
143 case EbtBool:
144 setBConst(constant.getBConst());
145 break;
146 case EbtFloat:
147 setBConst(constant.getFConst() != 0.0f);
148 break;
149 default:
150 return false;
151 }
152 break;
153 case EbtStruct: // Struct fields don't get cast
154 switch (constant.type)
155 {
156 case EbtInt:
157 setIConst(constant.getIConst());
158 break;
159 case EbtUInt:
160 setUConst(constant.getUConst());
161 break;
162 case EbtBool:
163 setBConst(constant.getBConst());
164 break;
165 case EbtFloat:
166 setFConst(constant.getFConst());
167 break;
168 default:
169 return false;
170 }
171 break;
172 default:
173 return false;
174 }
175
176 return true;
177}
178
179bool TConstantUnion::operator==(const int i) const
180{
181 return i == iConst;
182}
183
184bool TConstantUnion::operator==(const unsigned int u) const
185{
186 return u == uConst;
187}
188
189bool TConstantUnion::operator==(const float f) const
190{
191 return f == fConst;
192}
193
194bool TConstantUnion::operator==(const bool b) const
195{
196 return b == bConst;
197}
198
199bool TConstantUnion::operator==(const TConstantUnion &constant) const
200{
201 if (constant.type != type)
202 return false;
203
204 switch (type)
205 {
206 case EbtInt:
207 return constant.iConst == iConst;
208 case EbtUInt:
209 return constant.uConst == uConst;
210 case EbtFloat:
211 return constant.fConst == fConst;
212 case EbtBool:
213 return constant.bConst == bConst;
214 default:
215 return false;
216 }
217}
218
219bool TConstantUnion::operator!=(const int i) const
220{
221 return !operator==(i);
222}
223
224bool TConstantUnion::operator!=(const unsigned int u) const
225{
226 return !operator==(u);
227}
228
229bool TConstantUnion::operator!=(const float f) const
230{
231 return !operator==(f);
232}
233
234bool TConstantUnion::operator!=(const bool b) const
235{
236 return !operator==(b);
237}
238
239bool TConstantUnion::operator!=(const TConstantUnion &constant) const
240{
241 return !operator==(constant);
242}
243
244bool TConstantUnion::operator>(const TConstantUnion &constant) const
245{
246 ASSERT(type == constant.type);
247 switch (type)
248 {
249 case EbtInt:
250 return iConst > constant.iConst;
251 case EbtUInt:
252 return uConst > constant.uConst;
253 case EbtFloat:
254 return fConst > constant.fConst;
255 default:
256 return false; // Invalid operation, handled at semantic analysis
257 }
258}
259
260bool TConstantUnion::operator<(const TConstantUnion &constant) const
261{
262 ASSERT(type == constant.type);
263 switch (type)
264 {
265 case EbtInt:
266 return iConst < constant.iConst;
267 case EbtUInt:
268 return uConst < constant.uConst;
269 case EbtFloat:
270 return fConst < constant.fConst;
271 default:
272 return false; // Invalid operation, handled at semantic analysis
273 }
274}
275
276// static
277TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,
278 const TConstantUnion &rhs,
Jamie Madill5db69f52016-09-15 12:47:32 -0400279 TDiagnostics *diag,
280 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400281{
282 TConstantUnion returnValue;
283 ASSERT(lhs.type == rhs.type);
284 switch (lhs.type)
285 {
286 case EbtInt:
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100287 returnValue.setIConst(gl::WrappingSum<int>(lhs.iConst, rhs.iConst));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400288 break;
289 case EbtUInt:
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100290 returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400291 break;
292 case EbtFloat:
Jamie Madill5db69f52016-09-15 12:47:32 -0400293 returnValue.setFConst(CheckedSum<float>(lhs.fConst, rhs.fConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400294 break;
295 default:
296 UNREACHABLE();
297 }
298
299 return returnValue;
300}
301
302// static
303TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
304 const TConstantUnion &rhs,
Jamie Madill5db69f52016-09-15 12:47:32 -0400305 TDiagnostics *diag,
306 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400307{
308 TConstantUnion returnValue;
309 ASSERT(lhs.type == rhs.type);
310 switch (lhs.type)
311 {
312 case EbtInt:
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100313 returnValue.setIConst(gl::WrappingDiff<int>(lhs.iConst, rhs.iConst));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400314 break;
315 case EbtUInt:
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100316 returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400317 break;
318 case EbtFloat:
Jamie Madill5db69f52016-09-15 12:47:32 -0400319 returnValue.setFConst(CheckedDiff<float>(lhs.fConst, rhs.fConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400320 break;
321 default:
322 UNREACHABLE();
323 }
324
325 return returnValue;
326}
327
328// static
329TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
330 const TConstantUnion &rhs,
Jamie Madill5db69f52016-09-15 12:47:32 -0400331 TDiagnostics *diag,
332 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400333{
334 TConstantUnion returnValue;
335 ASSERT(lhs.type == rhs.type);
336 switch (lhs.type)
337 {
338 case EbtInt:
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100339 returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400340 break;
341 case EbtUInt:
Olli Etuaho1be4d492016-09-27 11:15:38 +0100342 // Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely on that
343 // to implement wrapping multiplication.
344 returnValue.setUConst(lhs.uConst * rhs.uConst);
Jamie Madill47cb73a2016-09-09 11:41:44 -0400345 break;
346 case EbtFloat:
Jamie Madill5db69f52016-09-15 12:47:32 -0400347 returnValue.setFConst(CheckedMul<float>(lhs.fConst, rhs.fConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400348 break;
349 default:
350 UNREACHABLE();
351 }
352
353 return returnValue;
354}
355
356TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const
357{
358 TConstantUnion returnValue;
359 ASSERT(type == constant.type);
360 switch (type)
361 {
362 case EbtInt:
363 returnValue.setIConst(iConst % constant.iConst);
364 break;
365 case EbtUInt:
366 returnValue.setUConst(uConst % constant.uConst);
367 break;
368 default:
369 UNREACHABLE();
370 }
371
372 return returnValue;
373}
374
Jamie Madill596018c2016-09-21 12:57:03 -0400375// static
376TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs,
377 const TConstantUnion &rhs,
378 TDiagnostics *diag,
379 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400380{
381 TConstantUnion returnValue;
Olli Etuaho2cacb772016-09-26 08:50:40 +0100382 ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
383 ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
Olli Etuaho43103542016-10-10 12:28:13 +0100384 if ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
385 (rhs.type == EbtUInt && rhs.uConst > 31u))
Olli Etuaho2cacb772016-09-26 08:50:40 +0100386 {
387 diag->error(line, "Undefined shift (operand out of range)", ">>", "");
388 switch (lhs.type)
389 {
390 case EbtInt:
391 returnValue.setIConst(0);
392 break;
393 case EbtUInt:
394 returnValue.setUConst(0u);
395 break;
396 default:
397 UNREACHABLE();
398 }
399 return returnValue;
400 }
401
Jamie Madill596018c2016-09-21 12:57:03 -0400402 switch (lhs.type)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400403 {
404 case EbtInt:
Olli Etuaho43103542016-10-10 12:28:13 +0100405 {
406 unsigned int shiftOffset = 0;
Olli Etuaho2cacb772016-09-26 08:50:40 +0100407 switch (rhs.type)
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400408 {
Olli Etuaho2cacb772016-09-26 08:50:40 +0100409 case EbtInt:
Olli Etuaho43103542016-10-10 12:28:13 +0100410 shiftOffset = static_cast<unsigned int>(rhs.iConst);
Olli Etuaho2cacb772016-09-26 08:50:40 +0100411 break;
412 case EbtUInt:
Olli Etuaho43103542016-10-10 12:28:13 +0100413 shiftOffset = rhs.uConst;
Olli Etuaho2cacb772016-09-26 08:50:40 +0100414 break;
415 default:
416 UNREACHABLE();
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400417 }
Olli Etuaho43103542016-10-10 12:28:13 +0100418 if (shiftOffset > 0)
419 {
420 // ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend
421 // the sign bit." In C++ shifting negative integers is undefined, so we implement
422 // extending the sign bit manually.
423 bool extendSignBit = false;
424 int lhsSafe = lhs.iConst;
425 if (lhsSafe < 0)
426 {
427 extendSignBit = true;
428 // Clear the sign bit so that bitshift right is defined in C++.
429 lhsSafe &= 0x7fffffff;
430 ASSERT(lhsSafe > 0);
431 }
432 returnValue.setIConst(lhsSafe >> shiftOffset);
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400433
Olli Etuaho43103542016-10-10 12:28:13 +0100434 // Manually fill in the extended sign bit if necessary.
435 if (extendSignBit)
436 {
437 int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset));
438 returnValue.setIConst(returnValue.getIConst() | extendedSignBit);
439 }
440 }
441 else
442 {
443 returnValue.setIConst(rhs.iConst);
444 }
445 break;
446 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400447 case EbtUInt:
Olli Etuaho2cacb772016-09-26 08:50:40 +0100448 switch (rhs.type)
449 {
450 case EbtInt:
451 returnValue.setUConst(lhs.uConst >> rhs.iConst);
452 break;
453 case EbtUInt:
454 returnValue.setUConst(lhs.uConst >> rhs.uConst);
455 break;
456 default:
457 UNREACHABLE();
458 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400459 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400460
Jamie Madill47cb73a2016-09-09 11:41:44 -0400461 default:
462 UNREACHABLE();
463 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400464 return returnValue;
465}
466
Jamie Madill596018c2016-09-21 12:57:03 -0400467// static
468TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,
469 const TConstantUnion &rhs,
470 TDiagnostics *diag,
471 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400472{
473 TConstantUnion returnValue;
Olli Etuaho2cacb772016-09-26 08:50:40 +0100474 ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
475 ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
Olli Etuaho43103542016-10-10 12:28:13 +0100476 if ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
477 (rhs.type == EbtUInt && rhs.uConst > 31u))
Olli Etuaho2cacb772016-09-26 08:50:40 +0100478 {
479 diag->error(line, "Undefined shift (operand out of range)", "<<", "");
480 switch (lhs.type)
481 {
482 case EbtInt:
483 returnValue.setIConst(0);
484 break;
485 case EbtUInt:
486 returnValue.setUConst(0u);
487 break;
488 default:
489 UNREACHABLE();
490 }
491 return returnValue;
492 }
493
Jamie Madill596018c2016-09-21 12:57:03 -0400494 switch (lhs.type)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400495 {
496 case EbtInt:
Olli Etuaho2cacb772016-09-26 08:50:40 +0100497 switch (rhs.type)
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400498 {
Olli Etuaho43103542016-10-10 12:28:13 +0100499 // Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that
500 // lhs is "interpreted as a bit pattern". This also avoids the possibility of signed
501 // integer overflow or undefined shift of a negative integer.
Olli Etuaho2cacb772016-09-26 08:50:40 +0100502 case EbtInt:
Olli Etuaho43103542016-10-10 12:28:13 +0100503 returnValue.setIConst(
504 static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.iConst));
Olli Etuaho2cacb772016-09-26 08:50:40 +0100505 break;
506 case EbtUInt:
Olli Etuaho43103542016-10-10 12:28:13 +0100507 returnValue.setIConst(
508 static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.uConst));
Olli Etuaho2cacb772016-09-26 08:50:40 +0100509 break;
510 default:
511 UNREACHABLE();
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400512 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400513 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400514
Jamie Madill47cb73a2016-09-09 11:41:44 -0400515 case EbtUInt:
Olli Etuaho2cacb772016-09-26 08:50:40 +0100516 switch (rhs.type)
517 {
518 case EbtInt:
519 returnValue.setUConst(lhs.uConst << rhs.iConst);
520 break;
521 case EbtUInt:
522 returnValue.setUConst(lhs.uConst << rhs.uConst);
523 break;
524 default:
525 UNREACHABLE();
526 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400527 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400528
Jamie Madill47cb73a2016-09-09 11:41:44 -0400529 default:
530 UNREACHABLE();
531 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400532 return returnValue;
533}
534
535TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
536{
537 TConstantUnion returnValue;
538 ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
539 switch (type)
540 {
541 case EbtInt:
542 returnValue.setIConst(iConst & constant.iConst);
543 break;
544 case EbtUInt:
545 returnValue.setUConst(uConst & constant.uConst);
546 break;
547 default:
548 UNREACHABLE();
549 }
550
551 return returnValue;
552}
553
554TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
555{
556 TConstantUnion returnValue;
557 ASSERT(type == constant.type);
558 switch (type)
559 {
560 case EbtInt:
561 returnValue.setIConst(iConst | constant.iConst);
562 break;
563 case EbtUInt:
564 returnValue.setUConst(uConst | constant.uConst);
565 break;
566 default:
567 UNREACHABLE();
568 }
569
570 return returnValue;
571}
572
573TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
574{
575 TConstantUnion returnValue;
576 ASSERT(type == constant.type);
577 switch (type)
578 {
579 case EbtInt:
580 returnValue.setIConst(iConst ^ constant.iConst);
581 break;
582 case EbtUInt:
583 returnValue.setUConst(uConst ^ constant.uConst);
584 break;
585 default:
586 UNREACHABLE();
587 }
588
589 return returnValue;
590}
591
592TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
593{
594 TConstantUnion returnValue;
595 ASSERT(type == constant.type);
596 switch (type)
597 {
598 case EbtBool:
599 returnValue.setBConst(bConst && constant.bConst);
600 break;
601 default:
602 UNREACHABLE();
603 }
604
605 return returnValue;
606}
607
608TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
609{
610 TConstantUnion returnValue;
611 ASSERT(type == constant.type);
612 switch (type)
613 {
614 case EbtBool:
615 returnValue.setBConst(bConst || constant.bConst);
616 break;
617 default:
618 UNREACHABLE();
619 }
620
621 return returnValue;
622}