Line data Source code
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 :
13 : namespace sh
14 : {
15 :
16 : namespace
17 : {
18 :
19 0 : float CheckedSum(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
20 : {
21 0 : float result = lhs + rhs;
22 0 : if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
23 : {
24 0 : diag->warning(line, "Constant folded undefined addition generated NaN", "+", "");
25 : }
26 0 : else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
27 : {
28 0 : diag->warning(line, "Constant folded addition overflowed to infinity", "+", "");
29 : }
30 0 : return result;
31 : }
32 :
33 0 : float CheckedDiff(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
34 : {
35 0 : float result = lhs - rhs;
36 0 : if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
37 : {
38 0 : diag->warning(line, "Constant folded undefined subtraction generated NaN", "-", "");
39 : }
40 0 : else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
41 : {
42 0 : diag->warning(line, "Constant folded subtraction overflowed to infinity", "-", "");
43 : }
44 0 : return result;
45 : }
46 :
47 0 : float CheckedMul(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
48 : {
49 0 : float result = lhs * rhs;
50 0 : if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
51 : {
52 0 : diag->warning(line, "Constant folded undefined multiplication generated NaN", "*", "");
53 : }
54 0 : else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
55 : {
56 0 : diag->warning(line, "Constant folded multiplication overflowed to infinity", "*", "");
57 : }
58 0 : return result;
59 : }
60 :
61 : } // anonymous namespace
62 :
63 0 : TConstantUnion::TConstantUnion()
64 : {
65 0 : iConst = 0;
66 0 : type = EbtVoid;
67 0 : }
68 :
69 0 : bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant)
70 : {
71 0 : switch (newType)
72 : {
73 : case EbtFloat:
74 0 : switch (constant.type)
75 : {
76 : case EbtInt:
77 0 : setFConst(static_cast<float>(constant.getIConst()));
78 0 : break;
79 : case EbtUInt:
80 0 : setFConst(static_cast<float>(constant.getUConst()));
81 0 : break;
82 : case EbtBool:
83 0 : setFConst(static_cast<float>(constant.getBConst()));
84 0 : break;
85 : case EbtFloat:
86 0 : setFConst(static_cast<float>(constant.getFConst()));
87 0 : break;
88 : default:
89 0 : return false;
90 : }
91 0 : break;
92 : case EbtInt:
93 0 : switch (constant.type)
94 : {
95 : case EbtInt:
96 0 : setIConst(static_cast<int>(constant.getIConst()));
97 0 : break;
98 : case EbtUInt:
99 0 : setIConst(static_cast<int>(constant.getUConst()));
100 0 : break;
101 : case EbtBool:
102 0 : setIConst(static_cast<int>(constant.getBConst()));
103 0 : break;
104 : case EbtFloat:
105 0 : setIConst(static_cast<int>(constant.getFConst()));
106 0 : break;
107 : default:
108 0 : return false;
109 : }
110 0 : break;
111 : case EbtUInt:
112 0 : switch (constant.type)
113 : {
114 : case EbtInt:
115 0 : setUConst(static_cast<unsigned int>(constant.getIConst()));
116 0 : break;
117 : case EbtUInt:
118 0 : setUConst(static_cast<unsigned int>(constant.getUConst()));
119 0 : break;
120 : case EbtBool:
121 0 : setUConst(static_cast<unsigned int>(constant.getBConst()));
122 0 : break;
123 : case EbtFloat:
124 0 : setUConst(static_cast<unsigned int>(constant.getFConst()));
125 0 : break;
126 : default:
127 0 : return false;
128 : }
129 0 : break;
130 : case EbtBool:
131 0 : switch (constant.type)
132 : {
133 : case EbtInt:
134 0 : setBConst(constant.getIConst() != 0);
135 0 : break;
136 : case EbtUInt:
137 0 : setBConst(constant.getUConst() != 0);
138 0 : break;
139 : case EbtBool:
140 0 : setBConst(constant.getBConst());
141 0 : break;
142 : case EbtFloat:
143 0 : setBConst(constant.getFConst() != 0.0f);
144 0 : break;
145 : default:
146 0 : return false;
147 : }
148 0 : break;
149 : case EbtStruct: // Struct fields don't get cast
150 0 : switch (constant.type)
151 : {
152 : case EbtInt:
153 0 : setIConst(constant.getIConst());
154 0 : break;
155 : case EbtUInt:
156 0 : setUConst(constant.getUConst());
157 0 : break;
158 : case EbtBool:
159 0 : setBConst(constant.getBConst());
160 0 : break;
161 : case EbtFloat:
162 0 : setFConst(constant.getFConst());
163 0 : break;
164 : default:
165 0 : return false;
166 : }
167 0 : break;
168 : default:
169 0 : return false;
170 : }
171 :
172 0 : return true;
173 : }
174 :
175 0 : bool TConstantUnion::operator==(const int i) const
176 : {
177 0 : return i == iConst;
178 : }
179 :
180 0 : bool TConstantUnion::operator==(const unsigned int u) const
181 : {
182 0 : return u == uConst;
183 : }
184 :
185 0 : bool TConstantUnion::operator==(const float f) const
186 : {
187 0 : return f == fConst;
188 : }
189 :
190 0 : bool TConstantUnion::operator==(const bool b) const
191 : {
192 0 : return b == bConst;
193 : }
194 :
195 0 : bool TConstantUnion::operator==(const TConstantUnion &constant) const
196 : {
197 0 : if (constant.type != type)
198 0 : return false;
199 :
200 0 : switch (type)
201 : {
202 : case EbtInt:
203 0 : return constant.iConst == iConst;
204 : case EbtUInt:
205 0 : return constant.uConst == uConst;
206 : case EbtFloat:
207 0 : return constant.fConst == fConst;
208 : case EbtBool:
209 0 : return constant.bConst == bConst;
210 : default:
211 0 : return false;
212 : }
213 : }
214 :
215 0 : bool TConstantUnion::operator!=(const int i) const
216 : {
217 0 : return !operator==(i);
218 : }
219 :
220 0 : bool TConstantUnion::operator!=(const unsigned int u) const
221 : {
222 0 : return !operator==(u);
223 : }
224 :
225 0 : bool TConstantUnion::operator!=(const float f) const
226 : {
227 0 : return !operator==(f);
228 : }
229 :
230 0 : bool TConstantUnion::operator!=(const bool b) const
231 : {
232 0 : return !operator==(b);
233 : }
234 :
235 0 : bool TConstantUnion::operator!=(const TConstantUnion &constant) const
236 : {
237 0 : return !operator==(constant);
238 : }
239 :
240 0 : bool TConstantUnion::operator>(const TConstantUnion &constant) const
241 : {
242 0 : ASSERT(type == constant.type);
243 0 : switch (type)
244 : {
245 : case EbtInt:
246 0 : return iConst > constant.iConst;
247 : case EbtUInt:
248 0 : return uConst > constant.uConst;
249 : case EbtFloat:
250 0 : return fConst > constant.fConst;
251 : default:
252 0 : return false; // Invalid operation, handled at semantic analysis
253 : }
254 : }
255 :
256 0 : bool TConstantUnion::operator<(const TConstantUnion &constant) const
257 : {
258 0 : ASSERT(type == constant.type);
259 0 : switch (type)
260 : {
261 : case EbtInt:
262 0 : return iConst < constant.iConst;
263 : case EbtUInt:
264 0 : return uConst < constant.uConst;
265 : case EbtFloat:
266 0 : return fConst < constant.fConst;
267 : default:
268 0 : return false; // Invalid operation, handled at semantic analysis
269 : }
270 : }
271 :
272 : // static
273 0 : TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,
274 : const TConstantUnion &rhs,
275 : TDiagnostics *diag,
276 : const TSourceLoc &line)
277 : {
278 0 : TConstantUnion returnValue;
279 0 : ASSERT(lhs.type == rhs.type);
280 0 : switch (lhs.type)
281 : {
282 : case EbtInt:
283 0 : returnValue.setIConst(gl::WrappingSum<int>(lhs.iConst, rhs.iConst));
284 0 : break;
285 : case EbtUInt:
286 0 : returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst));
287 0 : break;
288 : case EbtFloat:
289 0 : returnValue.setFConst(CheckedSum(lhs.fConst, rhs.fConst, diag, line));
290 0 : break;
291 : default:
292 0 : UNREACHABLE();
293 : }
294 :
295 0 : return returnValue;
296 : }
297 :
298 : // static
299 0 : TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
300 : const TConstantUnion &rhs,
301 : TDiagnostics *diag,
302 : const TSourceLoc &line)
303 : {
304 0 : TConstantUnion returnValue;
305 0 : ASSERT(lhs.type == rhs.type);
306 0 : switch (lhs.type)
307 : {
308 : case EbtInt:
309 0 : returnValue.setIConst(gl::WrappingDiff<int>(lhs.iConst, rhs.iConst));
310 0 : break;
311 : case EbtUInt:
312 0 : returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst));
313 0 : break;
314 : case EbtFloat:
315 0 : returnValue.setFConst(CheckedDiff(lhs.fConst, rhs.fConst, diag, line));
316 0 : break;
317 : default:
318 0 : UNREACHABLE();
319 : }
320 :
321 0 : return returnValue;
322 : }
323 :
324 : // static
325 0 : TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
326 : const TConstantUnion &rhs,
327 : TDiagnostics *diag,
328 : const TSourceLoc &line)
329 : {
330 0 : TConstantUnion returnValue;
331 0 : ASSERT(lhs.type == rhs.type);
332 0 : switch (lhs.type)
333 : {
334 : case EbtInt:
335 0 : returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst));
336 0 : break;
337 : case EbtUInt:
338 : // Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely on that
339 : // to implement wrapping multiplication.
340 0 : returnValue.setUConst(lhs.uConst * rhs.uConst);
341 0 : break;
342 : case EbtFloat:
343 0 : returnValue.setFConst(CheckedMul(lhs.fConst, rhs.fConst, diag, line));
344 0 : break;
345 : default:
346 0 : UNREACHABLE();
347 : }
348 :
349 0 : return returnValue;
350 : }
351 :
352 0 : TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const
353 : {
354 0 : TConstantUnion returnValue;
355 0 : ASSERT(type == constant.type);
356 0 : switch (type)
357 : {
358 : case EbtInt:
359 0 : returnValue.setIConst(iConst % constant.iConst);
360 0 : break;
361 : case EbtUInt:
362 0 : returnValue.setUConst(uConst % constant.uConst);
363 0 : break;
364 : default:
365 0 : UNREACHABLE();
366 : }
367 :
368 0 : return returnValue;
369 : }
370 :
371 : // static
372 0 : TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs,
373 : const TConstantUnion &rhs,
374 : TDiagnostics *diag,
375 : const TSourceLoc &line)
376 : {
377 0 : TConstantUnion returnValue;
378 0 : ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
379 0 : ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
380 0 : if ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
381 0 : (rhs.type == EbtUInt && rhs.uConst > 31u))
382 : {
383 0 : diag->error(line, "Undefined shift (operand out of range)", ">>", "");
384 0 : switch (lhs.type)
385 : {
386 : case EbtInt:
387 0 : returnValue.setIConst(0);
388 0 : break;
389 : case EbtUInt:
390 0 : returnValue.setUConst(0u);
391 0 : break;
392 : default:
393 0 : UNREACHABLE();
394 : }
395 0 : return returnValue;
396 : }
397 :
398 0 : switch (lhs.type)
399 : {
400 : case EbtInt:
401 : {
402 0 : unsigned int shiftOffset = 0;
403 0 : switch (rhs.type)
404 : {
405 : case EbtInt:
406 0 : shiftOffset = static_cast<unsigned int>(rhs.iConst);
407 0 : break;
408 : case EbtUInt:
409 0 : shiftOffset = rhs.uConst;
410 0 : break;
411 : default:
412 0 : UNREACHABLE();
413 : }
414 0 : if (shiftOffset > 0)
415 : {
416 : // ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend
417 : // the sign bit." In C++ shifting negative integers is undefined, so we implement
418 : // extending the sign bit manually.
419 0 : int lhsSafe = lhs.iConst;
420 0 : if (lhsSafe == std::numeric_limits<int>::min())
421 : {
422 : // The min integer needs special treatment because only bit it has set is the
423 : // sign bit, which we clear later to implement safe right shift of negative
424 : // numbers.
425 0 : lhsSafe = -0x40000000;
426 0 : --shiftOffset;
427 : }
428 0 : if (shiftOffset > 0)
429 : {
430 0 : bool extendSignBit = false;
431 0 : if (lhsSafe < 0)
432 : {
433 0 : extendSignBit = true;
434 : // Clear the sign bit so that bitshift right is defined in C++.
435 0 : lhsSafe &= 0x7fffffff;
436 0 : ASSERT(lhsSafe > 0);
437 : }
438 0 : returnValue.setIConst(lhsSafe >> shiftOffset);
439 :
440 : // Manually fill in the extended sign bit if necessary.
441 0 : if (extendSignBit)
442 : {
443 0 : int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset));
444 0 : returnValue.setIConst(returnValue.getIConst() | extendedSignBit);
445 : }
446 : }
447 : else
448 : {
449 0 : returnValue.setIConst(lhsSafe);
450 : }
451 : }
452 : else
453 : {
454 0 : returnValue.setIConst(lhs.iConst);
455 : }
456 0 : break;
457 : }
458 : case EbtUInt:
459 0 : switch (rhs.type)
460 : {
461 : case EbtInt:
462 0 : returnValue.setUConst(lhs.uConst >> rhs.iConst);
463 0 : break;
464 : case EbtUInt:
465 0 : returnValue.setUConst(lhs.uConst >> rhs.uConst);
466 0 : break;
467 : default:
468 0 : UNREACHABLE();
469 : }
470 0 : break;
471 :
472 : default:
473 0 : UNREACHABLE();
474 : }
475 0 : return returnValue;
476 : }
477 :
478 : // static
479 0 : TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,
480 : const TConstantUnion &rhs,
481 : TDiagnostics *diag,
482 : const TSourceLoc &line)
483 : {
484 0 : TConstantUnion returnValue;
485 0 : ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
486 0 : ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
487 0 : if ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
488 0 : (rhs.type == EbtUInt && rhs.uConst > 31u))
489 : {
490 0 : diag->error(line, "Undefined shift (operand out of range)", "<<", "");
491 0 : switch (lhs.type)
492 : {
493 : case EbtInt:
494 0 : returnValue.setIConst(0);
495 0 : break;
496 : case EbtUInt:
497 0 : returnValue.setUConst(0u);
498 0 : break;
499 : default:
500 0 : UNREACHABLE();
501 : }
502 0 : return returnValue;
503 : }
504 :
505 0 : switch (lhs.type)
506 : {
507 : case EbtInt:
508 0 : switch (rhs.type)
509 : {
510 : // Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that
511 : // lhs is "interpreted as a bit pattern". This also avoids the possibility of signed
512 : // integer overflow or undefined shift of a negative integer.
513 : case EbtInt:
514 0 : returnValue.setIConst(
515 0 : static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.iConst));
516 0 : break;
517 : case EbtUInt:
518 0 : returnValue.setIConst(
519 0 : static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.uConst));
520 0 : break;
521 : default:
522 0 : UNREACHABLE();
523 : }
524 0 : break;
525 :
526 : case EbtUInt:
527 0 : switch (rhs.type)
528 : {
529 : case EbtInt:
530 0 : returnValue.setUConst(lhs.uConst << rhs.iConst);
531 0 : break;
532 : case EbtUInt:
533 0 : returnValue.setUConst(lhs.uConst << rhs.uConst);
534 0 : break;
535 : default:
536 0 : UNREACHABLE();
537 : }
538 0 : break;
539 :
540 : default:
541 0 : UNREACHABLE();
542 : }
543 0 : return returnValue;
544 : }
545 :
546 0 : TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
547 : {
548 0 : TConstantUnion returnValue;
549 0 : ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
550 0 : switch (type)
551 : {
552 : case EbtInt:
553 0 : returnValue.setIConst(iConst & constant.iConst);
554 0 : break;
555 : case EbtUInt:
556 0 : returnValue.setUConst(uConst & constant.uConst);
557 0 : break;
558 : default:
559 0 : UNREACHABLE();
560 : }
561 :
562 0 : return returnValue;
563 : }
564 :
565 0 : TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
566 : {
567 0 : TConstantUnion returnValue;
568 0 : ASSERT(type == constant.type);
569 0 : switch (type)
570 : {
571 : case EbtInt:
572 0 : returnValue.setIConst(iConst | constant.iConst);
573 0 : break;
574 : case EbtUInt:
575 0 : returnValue.setUConst(uConst | constant.uConst);
576 0 : break;
577 : default:
578 0 : UNREACHABLE();
579 : }
580 :
581 0 : return returnValue;
582 : }
583 :
584 0 : TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
585 : {
586 0 : TConstantUnion returnValue;
587 0 : ASSERT(type == constant.type);
588 0 : switch (type)
589 : {
590 : case EbtInt:
591 0 : returnValue.setIConst(iConst ^ constant.iConst);
592 0 : break;
593 : case EbtUInt:
594 0 : returnValue.setUConst(uConst ^ constant.uConst);
595 0 : break;
596 : default:
597 0 : UNREACHABLE();
598 : }
599 :
600 0 : return returnValue;
601 : }
602 :
603 0 : TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
604 : {
605 0 : TConstantUnion returnValue;
606 0 : ASSERT(type == constant.type);
607 0 : switch (type)
608 : {
609 : case EbtBool:
610 0 : returnValue.setBConst(bConst && constant.bConst);
611 0 : break;
612 : default:
613 0 : UNREACHABLE();
614 : }
615 :
616 0 : return returnValue;
617 : }
618 :
619 0 : TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
620 : {
621 0 : TConstantUnion returnValue;
622 0 : ASSERT(type == constant.type);
623 0 : switch (type)
624 : {
625 : case EbtBool:
626 0 : returnValue.setBConst(bConst || constant.bConst);
627 0 : break;
628 : default:
629 0 : UNREACHABLE();
630 : }
631 :
632 0 : return returnValue;
633 : }
634 :
635 : } // namespace sh
|