blob: 66f444b0b74deacfbe9c6023e7d9a6ed480e701c [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 Madill45bcc782016-11-07 13:58:48 -050014namespace sh
15{
16
Jamie Madill5db69f52016-09-15 12:47:32 -040017namespace
18{
19
20template <typename T>
21T CheckedSum(base::CheckedNumeric<T> lhs,
22 base::CheckedNumeric<T> rhs,
23 TDiagnostics *diag,
24 const TSourceLoc &line)
25{
26 ASSERT(lhs.IsValid() && rhs.IsValid());
27 auto result = lhs + rhs;
28 if (!result.IsValid())
29 {
30 diag->error(line, "Addition out of range", "*", "");
31 return 0;
32 }
33 return result.ValueOrDefault(0);
34}
35
36template <typename T>
37T CheckedDiff(base::CheckedNumeric<T> lhs,
38 base::CheckedNumeric<T> rhs,
39 TDiagnostics *diag,
40 const TSourceLoc &line)
41{
42 ASSERT(lhs.IsValid() && rhs.IsValid());
43 auto result = lhs - rhs;
44 if (!result.IsValid())
45 {
46 diag->error(line, "Difference out of range", "*", "");
47 return 0;
48 }
49 return result.ValueOrDefault(0);
50}
51
52template <typename T>
53T CheckedMul(base::CheckedNumeric<T> lhs,
54 base::CheckedNumeric<T> rhs,
55 TDiagnostics *diag,
56 const TSourceLoc &line)
57{
58 ASSERT(lhs.IsValid() && rhs.IsValid());
59 auto result = lhs * rhs;
60 if (!result.IsValid())
61 {
62 diag->error(line, "Multiplication out of range", "*", "");
63 return 0;
64 }
65 return result.ValueOrDefault(0);
66}
67
68} // anonymous namespace
69
Jamie Madill47cb73a2016-09-09 11:41:44 -040070TConstantUnion::TConstantUnion()
71{
72 iConst = 0;
73 type = EbtVoid;
74}
75
76bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant)
77{
78 switch (newType)
79 {
80 case EbtFloat:
81 switch (constant.type)
82 {
83 case EbtInt:
84 setFConst(static_cast<float>(constant.getIConst()));
85 break;
86 case EbtUInt:
87 setFConst(static_cast<float>(constant.getUConst()));
88 break;
89 case EbtBool:
90 setFConst(static_cast<float>(constant.getBConst()));
91 break;
92 case EbtFloat:
93 setFConst(static_cast<float>(constant.getFConst()));
94 break;
95 default:
96 return false;
97 }
98 break;
99 case EbtInt:
100 switch (constant.type)
101 {
102 case EbtInt:
103 setIConst(static_cast<int>(constant.getIConst()));
104 break;
105 case EbtUInt:
106 setIConst(static_cast<int>(constant.getUConst()));
107 break;
108 case EbtBool:
109 setIConst(static_cast<int>(constant.getBConst()));
110 break;
111 case EbtFloat:
112 setIConst(static_cast<int>(constant.getFConst()));
113 break;
114 default:
115 return false;
116 }
117 break;
118 case EbtUInt:
119 switch (constant.type)
120 {
121 case EbtInt:
122 setUConst(static_cast<unsigned int>(constant.getIConst()));
123 break;
124 case EbtUInt:
125 setUConst(static_cast<unsigned int>(constant.getUConst()));
126 break;
127 case EbtBool:
128 setUConst(static_cast<unsigned int>(constant.getBConst()));
129 break;
130 case EbtFloat:
131 setUConst(static_cast<unsigned int>(constant.getFConst()));
132 break;
133 default:
134 return false;
135 }
136 break;
137 case EbtBool:
138 switch (constant.type)
139 {
140 case EbtInt:
141 setBConst(constant.getIConst() != 0);
142 break;
143 case EbtUInt:
144 setBConst(constant.getUConst() != 0);
145 break;
146 case EbtBool:
147 setBConst(constant.getBConst());
148 break;
149 case EbtFloat:
150 setBConst(constant.getFConst() != 0.0f);
151 break;
152 default:
153 return false;
154 }
155 break;
156 case EbtStruct: // Struct fields don't get cast
157 switch (constant.type)
158 {
159 case EbtInt:
160 setIConst(constant.getIConst());
161 break;
162 case EbtUInt:
163 setUConst(constant.getUConst());
164 break;
165 case EbtBool:
166 setBConst(constant.getBConst());
167 break;
168 case EbtFloat:
169 setFConst(constant.getFConst());
170 break;
171 default:
172 return false;
173 }
174 break;
175 default:
176 return false;
177 }
178
179 return true;
180}
181
182bool TConstantUnion::operator==(const int i) const
183{
184 return i == iConst;
185}
186
187bool TConstantUnion::operator==(const unsigned int u) const
188{
189 return u == uConst;
190}
191
192bool TConstantUnion::operator==(const float f) const
193{
194 return f == fConst;
195}
196
197bool TConstantUnion::operator==(const bool b) const
198{
199 return b == bConst;
200}
201
202bool TConstantUnion::operator==(const TConstantUnion &constant) const
203{
204 if (constant.type != type)
205 return false;
206
207 switch (type)
208 {
209 case EbtInt:
210 return constant.iConst == iConst;
211 case EbtUInt:
212 return constant.uConst == uConst;
213 case EbtFloat:
214 return constant.fConst == fConst;
215 case EbtBool:
216 return constant.bConst == bConst;
217 default:
218 return false;
219 }
220}
221
222bool TConstantUnion::operator!=(const int i) const
223{
224 return !operator==(i);
225}
226
227bool TConstantUnion::operator!=(const unsigned int u) const
228{
229 return !operator==(u);
230}
231
232bool TConstantUnion::operator!=(const float f) const
233{
234 return !operator==(f);
235}
236
237bool TConstantUnion::operator!=(const bool b) const
238{
239 return !operator==(b);
240}
241
242bool TConstantUnion::operator!=(const TConstantUnion &constant) const
243{
244 return !operator==(constant);
245}
246
247bool TConstantUnion::operator>(const TConstantUnion &constant) const
248{
249 ASSERT(type == constant.type);
250 switch (type)
251 {
252 case EbtInt:
253 return iConst > constant.iConst;
254 case EbtUInt:
255 return uConst > constant.uConst;
256 case EbtFloat:
257 return fConst > constant.fConst;
258 default:
259 return false; // Invalid operation, handled at semantic analysis
260 }
261}
262
263bool TConstantUnion::operator<(const TConstantUnion &constant) const
264{
265 ASSERT(type == constant.type);
266 switch (type)
267 {
268 case EbtInt:
269 return iConst < constant.iConst;
270 case EbtUInt:
271 return uConst < constant.uConst;
272 case EbtFloat:
273 return fConst < constant.fConst;
274 default:
275 return false; // Invalid operation, handled at semantic analysis
276 }
277}
278
279// static
280TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,
281 const TConstantUnion &rhs,
Jamie Madill5db69f52016-09-15 12:47:32 -0400282 TDiagnostics *diag,
283 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400284{
285 TConstantUnion returnValue;
286 ASSERT(lhs.type == rhs.type);
287 switch (lhs.type)
288 {
289 case EbtInt:
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100290 returnValue.setIConst(gl::WrappingSum<int>(lhs.iConst, rhs.iConst));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400291 break;
292 case EbtUInt:
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100293 returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400294 break;
295 case EbtFloat:
Jamie Madill5db69f52016-09-15 12:47:32 -0400296 returnValue.setFConst(CheckedSum<float>(lhs.fConst, rhs.fConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400297 break;
298 default:
299 UNREACHABLE();
300 }
301
302 return returnValue;
303}
304
305// static
306TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
307 const TConstantUnion &rhs,
Jamie Madill5db69f52016-09-15 12:47:32 -0400308 TDiagnostics *diag,
309 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400310{
311 TConstantUnion returnValue;
312 ASSERT(lhs.type == rhs.type);
313 switch (lhs.type)
314 {
315 case EbtInt:
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100316 returnValue.setIConst(gl::WrappingDiff<int>(lhs.iConst, rhs.iConst));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400317 break;
318 case EbtUInt:
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100319 returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400320 break;
321 case EbtFloat:
Jamie Madill5db69f52016-09-15 12:47:32 -0400322 returnValue.setFConst(CheckedDiff<float>(lhs.fConst, rhs.fConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400323 break;
324 default:
325 UNREACHABLE();
326 }
327
328 return returnValue;
329}
330
331// static
332TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
333 const TConstantUnion &rhs,
Jamie Madill5db69f52016-09-15 12:47:32 -0400334 TDiagnostics *diag,
335 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400336{
337 TConstantUnion returnValue;
338 ASSERT(lhs.type == rhs.type);
339 switch (lhs.type)
340 {
341 case EbtInt:
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100342 returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400343 break;
344 case EbtUInt:
Olli Etuaho1be4d492016-09-27 11:15:38 +0100345 // Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely on that
346 // to implement wrapping multiplication.
347 returnValue.setUConst(lhs.uConst * rhs.uConst);
Jamie Madill47cb73a2016-09-09 11:41:44 -0400348 break;
349 case EbtFloat:
Jamie Madill5db69f52016-09-15 12:47:32 -0400350 returnValue.setFConst(CheckedMul<float>(lhs.fConst, rhs.fConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400351 break;
352 default:
353 UNREACHABLE();
354 }
355
356 return returnValue;
357}
358
359TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const
360{
361 TConstantUnion returnValue;
362 ASSERT(type == constant.type);
363 switch (type)
364 {
365 case EbtInt:
366 returnValue.setIConst(iConst % constant.iConst);
367 break;
368 case EbtUInt:
369 returnValue.setUConst(uConst % constant.uConst);
370 break;
371 default:
372 UNREACHABLE();
373 }
374
375 return returnValue;
376}
377
Jamie Madill596018c2016-09-21 12:57:03 -0400378// static
379TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs,
380 const TConstantUnion &rhs,
381 TDiagnostics *diag,
382 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400383{
384 TConstantUnion returnValue;
Olli Etuaho2cacb772016-09-26 08:50:40 +0100385 ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
386 ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
Olli Etuaho43103542016-10-10 12:28:13 +0100387 if ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
388 (rhs.type == EbtUInt && rhs.uConst > 31u))
Olli Etuaho2cacb772016-09-26 08:50:40 +0100389 {
390 diag->error(line, "Undefined shift (operand out of range)", ">>", "");
391 switch (lhs.type)
392 {
393 case EbtInt:
394 returnValue.setIConst(0);
395 break;
396 case EbtUInt:
397 returnValue.setUConst(0u);
398 break;
399 default:
400 UNREACHABLE();
401 }
402 return returnValue;
403 }
404
Jamie Madill596018c2016-09-21 12:57:03 -0400405 switch (lhs.type)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400406 {
407 case EbtInt:
Olli Etuaho43103542016-10-10 12:28:13 +0100408 {
409 unsigned int shiftOffset = 0;
Olli Etuaho2cacb772016-09-26 08:50:40 +0100410 switch (rhs.type)
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400411 {
Olli Etuaho2cacb772016-09-26 08:50:40 +0100412 case EbtInt:
Olli Etuaho43103542016-10-10 12:28:13 +0100413 shiftOffset = static_cast<unsigned int>(rhs.iConst);
Olli Etuaho2cacb772016-09-26 08:50:40 +0100414 break;
415 case EbtUInt:
Olli Etuaho43103542016-10-10 12:28:13 +0100416 shiftOffset = rhs.uConst;
Olli Etuaho2cacb772016-09-26 08:50:40 +0100417 break;
418 default:
419 UNREACHABLE();
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400420 }
Olli Etuaho43103542016-10-10 12:28:13 +0100421 if (shiftOffset > 0)
422 {
423 // ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend
424 // the sign bit." In C++ shifting negative integers is undefined, so we implement
425 // extending the sign bit manually.
Olli Etuaho43103542016-10-10 12:28:13 +0100426 int lhsSafe = lhs.iConst;
Olli Etuaho55644212016-11-08 11:07:34 +0000427 if (lhsSafe == std::numeric_limits<int>::min())
Olli Etuaho43103542016-10-10 12:28:13 +0100428 {
Olli Etuaho55644212016-11-08 11:07:34 +0000429 // The min integer needs special treatment because only bit it has set is the
430 // sign bit, which we clear later to implement safe right shift of negative
431 // numbers.
432 lhsSafe = -0x40000000;
433 --shiftOffset;
Olli Etuaho43103542016-10-10 12:28:13 +0100434 }
Olli Etuaho55644212016-11-08 11:07:34 +0000435 if (shiftOffset > 0)
Olli Etuaho43103542016-10-10 12:28:13 +0100436 {
Olli Etuaho55644212016-11-08 11:07:34 +0000437 bool extendSignBit = false;
438 if (lhsSafe < 0)
439 {
440 extendSignBit = true;
441 // Clear the sign bit so that bitshift right is defined in C++.
442 lhsSafe &= 0x7fffffff;
443 ASSERT(lhsSafe > 0);
444 }
445 returnValue.setIConst(lhsSafe >> shiftOffset);
446
447 // Manually fill in the extended sign bit if necessary.
448 if (extendSignBit)
449 {
450 int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset));
451 returnValue.setIConst(returnValue.getIConst() | extendedSignBit);
452 }
453 }
454 else
455 {
456 returnValue.setIConst(lhsSafe);
Olli Etuaho43103542016-10-10 12:28:13 +0100457 }
458 }
459 else
460 {
Olli Etuaho55644212016-11-08 11:07:34 +0000461 returnValue.setIConst(lhs.iConst);
Olli Etuaho43103542016-10-10 12:28:13 +0100462 }
463 break;
464 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400465 case EbtUInt:
Olli Etuaho2cacb772016-09-26 08:50:40 +0100466 switch (rhs.type)
467 {
468 case EbtInt:
469 returnValue.setUConst(lhs.uConst >> rhs.iConst);
470 break;
471 case EbtUInt:
472 returnValue.setUConst(lhs.uConst >> rhs.uConst);
473 break;
474 default:
475 UNREACHABLE();
476 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400477 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400478
Jamie Madill47cb73a2016-09-09 11:41:44 -0400479 default:
480 UNREACHABLE();
481 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400482 return returnValue;
483}
484
Jamie Madill596018c2016-09-21 12:57:03 -0400485// static
486TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,
487 const TConstantUnion &rhs,
488 TDiagnostics *diag,
489 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400490{
491 TConstantUnion returnValue;
Olli Etuaho2cacb772016-09-26 08:50:40 +0100492 ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
493 ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
Olli Etuaho43103542016-10-10 12:28:13 +0100494 if ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
495 (rhs.type == EbtUInt && rhs.uConst > 31u))
Olli Etuaho2cacb772016-09-26 08:50:40 +0100496 {
497 diag->error(line, "Undefined shift (operand out of range)", "<<", "");
498 switch (lhs.type)
499 {
500 case EbtInt:
501 returnValue.setIConst(0);
502 break;
503 case EbtUInt:
504 returnValue.setUConst(0u);
505 break;
506 default:
507 UNREACHABLE();
508 }
509 return returnValue;
510 }
511
Jamie Madill596018c2016-09-21 12:57:03 -0400512 switch (lhs.type)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400513 {
514 case EbtInt:
Olli Etuaho2cacb772016-09-26 08:50:40 +0100515 switch (rhs.type)
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400516 {
Olli Etuaho43103542016-10-10 12:28:13 +0100517 // Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that
518 // lhs is "interpreted as a bit pattern". This also avoids the possibility of signed
519 // integer overflow or undefined shift of a negative integer.
Olli Etuaho2cacb772016-09-26 08:50:40 +0100520 case EbtInt:
Olli Etuaho43103542016-10-10 12:28:13 +0100521 returnValue.setIConst(
522 static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.iConst));
Olli Etuaho2cacb772016-09-26 08:50:40 +0100523 break;
524 case EbtUInt:
Olli Etuaho43103542016-10-10 12:28:13 +0100525 returnValue.setIConst(
526 static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.uConst));
Olli Etuaho2cacb772016-09-26 08:50:40 +0100527 break;
528 default:
529 UNREACHABLE();
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400530 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400531 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400532
Jamie Madill47cb73a2016-09-09 11:41:44 -0400533 case EbtUInt:
Olli Etuaho2cacb772016-09-26 08:50:40 +0100534 switch (rhs.type)
535 {
536 case EbtInt:
537 returnValue.setUConst(lhs.uConst << rhs.iConst);
538 break;
539 case EbtUInt:
540 returnValue.setUConst(lhs.uConst << rhs.uConst);
541 break;
542 default:
543 UNREACHABLE();
544 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400545 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400546
Jamie Madill47cb73a2016-09-09 11:41:44 -0400547 default:
548 UNREACHABLE();
549 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400550 return returnValue;
551}
552
553TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
554{
555 TConstantUnion returnValue;
556 ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
557 switch (type)
558 {
559 case EbtInt:
560 returnValue.setIConst(iConst & constant.iConst);
561 break;
562 case EbtUInt:
563 returnValue.setUConst(uConst & constant.uConst);
564 break;
565 default:
566 UNREACHABLE();
567 }
568
569 return returnValue;
570}
571
572TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
573{
574 TConstantUnion returnValue;
575 ASSERT(type == constant.type);
576 switch (type)
577 {
578 case EbtInt:
579 returnValue.setIConst(iConst | constant.iConst);
580 break;
581 case EbtUInt:
582 returnValue.setUConst(uConst | constant.uConst);
583 break;
584 default:
585 UNREACHABLE();
586 }
587
588 return returnValue;
589}
590
591TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
592{
593 TConstantUnion returnValue;
594 ASSERT(type == constant.type);
595 switch (type)
596 {
597 case EbtInt:
598 returnValue.setIConst(iConst ^ constant.iConst);
599 break;
600 case EbtUInt:
601 returnValue.setUConst(uConst ^ constant.uConst);
602 break;
603 default:
604 UNREACHABLE();
605 }
606
607 return returnValue;
608}
609
610TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
611{
612 TConstantUnion returnValue;
613 ASSERT(type == constant.type);
614 switch (type)
615 {
616 case EbtBool:
617 returnValue.setBConst(bConst && constant.bConst);
618 break;
619 default:
620 UNREACHABLE();
621 }
622
623 return returnValue;
624}
625
626TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
627{
628 TConstantUnion returnValue;
629 ASSERT(type == constant.type);
630 switch (type)
631 {
632 case EbtBool:
633 returnValue.setBConst(bConst || constant.bConst);
634 break;
635 default:
636 UNREACHABLE();
637 }
638
639 return returnValue;
640}
Jamie Madill45bcc782016-11-07 13:58:48 -0500641
642} // namespace sh