blob: d2cd42233621d5dbec6afeaa7804fc18f9de030e [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"
Jamie Madill47cb73a2016-09-09 11:41:44 -040011#include "compiler/translator/Diagnostics.h"
12
Jamie Madill5db69f52016-09-15 12:47:32 -040013namespace
14{
15
16template <typename T>
17T CheckedSum(base::CheckedNumeric<T> lhs,
18 base::CheckedNumeric<T> rhs,
19 TDiagnostics *diag,
20 const TSourceLoc &line)
21{
22 ASSERT(lhs.IsValid() && rhs.IsValid());
23 auto result = lhs + rhs;
24 if (!result.IsValid())
25 {
26 diag->error(line, "Addition out of range", "*", "");
27 return 0;
28 }
29 return result.ValueOrDefault(0);
30}
31
32template <typename T>
33T CheckedDiff(base::CheckedNumeric<T> lhs,
34 base::CheckedNumeric<T> rhs,
35 TDiagnostics *diag,
36 const TSourceLoc &line)
37{
38 ASSERT(lhs.IsValid() && rhs.IsValid());
39 auto result = lhs - rhs;
40 if (!result.IsValid())
41 {
42 diag->error(line, "Difference out of range", "*", "");
43 return 0;
44 }
45 return result.ValueOrDefault(0);
46}
47
48template <typename T>
49T CheckedMul(base::CheckedNumeric<T> lhs,
50 base::CheckedNumeric<T> rhs,
51 TDiagnostics *diag,
52 const TSourceLoc &line)
53{
54 ASSERT(lhs.IsValid() && rhs.IsValid());
55 auto result = lhs * rhs;
56 if (!result.IsValid())
57 {
58 diag->error(line, "Multiplication out of range", "*", "");
59 return 0;
60 }
61 return result.ValueOrDefault(0);
62}
63
64} // anonymous namespace
65
Jamie Madill47cb73a2016-09-09 11:41:44 -040066TConstantUnion::TConstantUnion()
67{
68 iConst = 0;
69 type = EbtVoid;
70}
71
72bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant)
73{
74 switch (newType)
75 {
76 case EbtFloat:
77 switch (constant.type)
78 {
79 case EbtInt:
80 setFConst(static_cast<float>(constant.getIConst()));
81 break;
82 case EbtUInt:
83 setFConst(static_cast<float>(constant.getUConst()));
84 break;
85 case EbtBool:
86 setFConst(static_cast<float>(constant.getBConst()));
87 break;
88 case EbtFloat:
89 setFConst(static_cast<float>(constant.getFConst()));
90 break;
91 default:
92 return false;
93 }
94 break;
95 case EbtInt:
96 switch (constant.type)
97 {
98 case EbtInt:
99 setIConst(static_cast<int>(constant.getIConst()));
100 break;
101 case EbtUInt:
102 setIConst(static_cast<int>(constant.getUConst()));
103 break;
104 case EbtBool:
105 setIConst(static_cast<int>(constant.getBConst()));
106 break;
107 case EbtFloat:
108 setIConst(static_cast<int>(constant.getFConst()));
109 break;
110 default:
111 return false;
112 }
113 break;
114 case EbtUInt:
115 switch (constant.type)
116 {
117 case EbtInt:
118 setUConst(static_cast<unsigned int>(constant.getIConst()));
119 break;
120 case EbtUInt:
121 setUConst(static_cast<unsigned int>(constant.getUConst()));
122 break;
123 case EbtBool:
124 setUConst(static_cast<unsigned int>(constant.getBConst()));
125 break;
126 case EbtFloat:
127 setUConst(static_cast<unsigned int>(constant.getFConst()));
128 break;
129 default:
130 return false;
131 }
132 break;
133 case EbtBool:
134 switch (constant.type)
135 {
136 case EbtInt:
137 setBConst(constant.getIConst() != 0);
138 break;
139 case EbtUInt:
140 setBConst(constant.getUConst() != 0);
141 break;
142 case EbtBool:
143 setBConst(constant.getBConst());
144 break;
145 case EbtFloat:
146 setBConst(constant.getFConst() != 0.0f);
147 break;
148 default:
149 return false;
150 }
151 break;
152 case EbtStruct: // Struct fields don't get cast
153 switch (constant.type)
154 {
155 case EbtInt:
156 setIConst(constant.getIConst());
157 break;
158 case EbtUInt:
159 setUConst(constant.getUConst());
160 break;
161 case EbtBool:
162 setBConst(constant.getBConst());
163 break;
164 case EbtFloat:
165 setFConst(constant.getFConst());
166 break;
167 default:
168 return false;
169 }
170 break;
171 default:
172 return false;
173 }
174
175 return true;
176}
177
178bool TConstantUnion::operator==(const int i) const
179{
180 return i == iConst;
181}
182
183bool TConstantUnion::operator==(const unsigned int u) const
184{
185 return u == uConst;
186}
187
188bool TConstantUnion::operator==(const float f) const
189{
190 return f == fConst;
191}
192
193bool TConstantUnion::operator==(const bool b) const
194{
195 return b == bConst;
196}
197
198bool TConstantUnion::operator==(const TConstantUnion &constant) const
199{
200 if (constant.type != type)
201 return false;
202
203 switch (type)
204 {
205 case EbtInt:
206 return constant.iConst == iConst;
207 case EbtUInt:
208 return constant.uConst == uConst;
209 case EbtFloat:
210 return constant.fConst == fConst;
211 case EbtBool:
212 return constant.bConst == bConst;
213 default:
214 return false;
215 }
216}
217
218bool TConstantUnion::operator!=(const int i) const
219{
220 return !operator==(i);
221}
222
223bool TConstantUnion::operator!=(const unsigned int u) const
224{
225 return !operator==(u);
226}
227
228bool TConstantUnion::operator!=(const float f) const
229{
230 return !operator==(f);
231}
232
233bool TConstantUnion::operator!=(const bool b) const
234{
235 return !operator==(b);
236}
237
238bool TConstantUnion::operator!=(const TConstantUnion &constant) const
239{
240 return !operator==(constant);
241}
242
243bool TConstantUnion::operator>(const TConstantUnion &constant) const
244{
245 ASSERT(type == constant.type);
246 switch (type)
247 {
248 case EbtInt:
249 return iConst > constant.iConst;
250 case EbtUInt:
251 return uConst > constant.uConst;
252 case EbtFloat:
253 return fConst > constant.fConst;
254 default:
255 return false; // Invalid operation, handled at semantic analysis
256 }
257}
258
259bool TConstantUnion::operator<(const TConstantUnion &constant) const
260{
261 ASSERT(type == constant.type);
262 switch (type)
263 {
264 case EbtInt:
265 return iConst < constant.iConst;
266 case EbtUInt:
267 return uConst < constant.uConst;
268 case EbtFloat:
269 return fConst < constant.fConst;
270 default:
271 return false; // Invalid operation, handled at semantic analysis
272 }
273}
274
275// static
276TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,
277 const TConstantUnion &rhs,
Jamie Madill5db69f52016-09-15 12:47:32 -0400278 TDiagnostics *diag,
279 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400280{
281 TConstantUnion returnValue;
282 ASSERT(lhs.type == rhs.type);
283 switch (lhs.type)
284 {
285 case EbtInt:
Jamie Madill5db69f52016-09-15 12:47:32 -0400286 returnValue.setIConst(CheckedSum<int>(lhs.iConst, rhs.iConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400287 break;
288 case EbtUInt:
Jamie Madill5db69f52016-09-15 12:47:32 -0400289 returnValue.setUConst(CheckedSum<unsigned int>(lhs.uConst, rhs.uConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400290 break;
291 case EbtFloat:
Jamie Madill5db69f52016-09-15 12:47:32 -0400292 returnValue.setFConst(CheckedSum<float>(lhs.fConst, rhs.fConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400293 break;
294 default:
295 UNREACHABLE();
296 }
297
298 return returnValue;
299}
300
301// static
302TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
303 const TConstantUnion &rhs,
Jamie Madill5db69f52016-09-15 12:47:32 -0400304 TDiagnostics *diag,
305 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400306{
307 TConstantUnion returnValue;
308 ASSERT(lhs.type == rhs.type);
309 switch (lhs.type)
310 {
311 case EbtInt:
Jamie Madill5db69f52016-09-15 12:47:32 -0400312 returnValue.setIConst(CheckedDiff<int>(lhs.iConst, rhs.iConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400313 break;
314 case EbtUInt:
Jamie Madill5db69f52016-09-15 12:47:32 -0400315 returnValue.setUConst(CheckedDiff<unsigned int>(lhs.uConst, rhs.uConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400316 break;
317 case EbtFloat:
Jamie Madill5db69f52016-09-15 12:47:32 -0400318 returnValue.setFConst(CheckedDiff<float>(lhs.fConst, rhs.fConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400319 break;
320 default:
321 UNREACHABLE();
322 }
323
324 return returnValue;
325}
326
327// static
328TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
329 const TConstantUnion &rhs,
Jamie Madill5db69f52016-09-15 12:47:32 -0400330 TDiagnostics *diag,
331 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400332{
333 TConstantUnion returnValue;
334 ASSERT(lhs.type == rhs.type);
335 switch (lhs.type)
336 {
337 case EbtInt:
Jamie Madill5db69f52016-09-15 12:47:32 -0400338 returnValue.setIConst(CheckedMul<int>(lhs.iConst, rhs.iConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400339 break;
340 case EbtUInt:
Jamie Madill5db69f52016-09-15 12:47:32 -0400341 returnValue.setUConst(CheckedMul<unsigned int>(lhs.uConst, rhs.uConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400342 break;
343 case EbtFloat:
Jamie Madill5db69f52016-09-15 12:47:32 -0400344 returnValue.setFConst(CheckedMul<float>(lhs.fConst, rhs.fConst, diag, line));
Jamie Madill47cb73a2016-09-09 11:41:44 -0400345 break;
346 default:
347 UNREACHABLE();
348 }
349
350 return returnValue;
351}
352
353TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const
354{
355 TConstantUnion returnValue;
356 ASSERT(type == constant.type);
357 switch (type)
358 {
359 case EbtInt:
360 returnValue.setIConst(iConst % constant.iConst);
361 break;
362 case EbtUInt:
363 returnValue.setUConst(uConst % constant.uConst);
364 break;
365 default:
366 UNREACHABLE();
367 }
368
369 return returnValue;
370}
371
Jamie Madill596018c2016-09-21 12:57:03 -0400372// static
373TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs,
374 const TConstantUnion &rhs,
375 TDiagnostics *diag,
376 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400377{
378 TConstantUnion returnValue;
Olli Etuaho2cacb772016-09-26 08:50:40 +0100379 ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
380 ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
381 if ((lhs.type == EbtInt && lhs.iConst < 0) ||
382 (rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
383 (rhs.type == EbtUInt && rhs.uConst > 31))
384 {
385 diag->error(line, "Undefined shift (operand out of range)", ">>", "");
386 switch (lhs.type)
387 {
388 case EbtInt:
389 returnValue.setIConst(0);
390 break;
391 case EbtUInt:
392 returnValue.setUConst(0u);
393 break;
394 default:
395 UNREACHABLE();
396 }
397 return returnValue;
398 }
399
Jamie Madill596018c2016-09-21 12:57:03 -0400400 switch (lhs.type)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400401 {
402 case EbtInt:
Olli Etuaho2cacb772016-09-26 08:50:40 +0100403 switch (rhs.type)
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400404 {
Olli Etuaho2cacb772016-09-26 08:50:40 +0100405 case EbtInt:
406 returnValue.setIConst(lhs.iConst >> rhs.iConst);
407 break;
408 case EbtUInt:
409 returnValue.setIConst(lhs.iConst >> rhs.uConst);
410 break;
411 default:
412 UNREACHABLE();
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400413 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400414 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400415
Jamie Madill47cb73a2016-09-09 11:41:44 -0400416 case EbtUInt:
Olli Etuaho2cacb772016-09-26 08:50:40 +0100417 switch (rhs.type)
418 {
419 case EbtInt:
420 returnValue.setUConst(lhs.uConst >> rhs.iConst);
421 break;
422 case EbtUInt:
423 returnValue.setUConst(lhs.uConst >> rhs.uConst);
424 break;
425 default:
426 UNREACHABLE();
427 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400428 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400429
Jamie Madill47cb73a2016-09-09 11:41:44 -0400430 default:
431 UNREACHABLE();
432 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400433 return returnValue;
434}
435
Jamie Madill596018c2016-09-21 12:57:03 -0400436// static
437TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,
438 const TConstantUnion &rhs,
439 TDiagnostics *diag,
440 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400441{
442 TConstantUnion returnValue;
Olli Etuaho2cacb772016-09-26 08:50:40 +0100443 ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
444 ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
445 if ((lhs.type == EbtInt && lhs.iConst < 0) ||
446 (rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
447 (rhs.type == EbtUInt && rhs.uConst > 31))
448 {
449 diag->error(line, "Undefined shift (operand out of range)", "<<", "");
450 switch (lhs.type)
451 {
452 case EbtInt:
453 returnValue.setIConst(0);
454 break;
455 case EbtUInt:
456 returnValue.setUConst(0u);
457 break;
458 default:
459 UNREACHABLE();
460 }
461 return returnValue;
462 }
463
Jamie Madill596018c2016-09-21 12:57:03 -0400464 switch (lhs.type)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400465 {
466 case EbtInt:
Olli Etuaho2cacb772016-09-26 08:50:40 +0100467 switch (rhs.type)
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400468 {
Olli Etuaho2cacb772016-09-26 08:50:40 +0100469 case EbtInt:
470 returnValue.setIConst(lhs.iConst << rhs.iConst);
471 break;
472 case EbtUInt:
473 returnValue.setIConst(lhs.iConst << rhs.uConst);
474 break;
475 default:
476 UNREACHABLE();
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400477 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400478 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400479
Jamie Madill47cb73a2016-09-09 11:41:44 -0400480 case EbtUInt:
Olli Etuaho2cacb772016-09-26 08:50:40 +0100481 switch (rhs.type)
482 {
483 case EbtInt:
484 returnValue.setUConst(lhs.uConst << rhs.iConst);
485 break;
486 case EbtUInt:
487 returnValue.setUConst(lhs.uConst << rhs.uConst);
488 break;
489 default:
490 UNREACHABLE();
491 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400492 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400493
Jamie Madill47cb73a2016-09-09 11:41:44 -0400494 default:
495 UNREACHABLE();
496 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400497 return returnValue;
498}
499
500TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
501{
502 TConstantUnion returnValue;
503 ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
504 switch (type)
505 {
506 case EbtInt:
507 returnValue.setIConst(iConst & constant.iConst);
508 break;
509 case EbtUInt:
510 returnValue.setUConst(uConst & constant.uConst);
511 break;
512 default:
513 UNREACHABLE();
514 }
515
516 return returnValue;
517}
518
519TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
520{
521 TConstantUnion returnValue;
522 ASSERT(type == constant.type);
523 switch (type)
524 {
525 case EbtInt:
526 returnValue.setIConst(iConst | constant.iConst);
527 break;
528 case EbtUInt:
529 returnValue.setUConst(uConst | constant.uConst);
530 break;
531 default:
532 UNREACHABLE();
533 }
534
535 return returnValue;
536}
537
538TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
539{
540 TConstantUnion returnValue;
541 ASSERT(type == constant.type);
542 switch (type)
543 {
544 case EbtInt:
545 returnValue.setIConst(iConst ^ constant.iConst);
546 break;
547 case EbtUInt:
548 returnValue.setUConst(uConst ^ constant.uConst);
549 break;
550 default:
551 UNREACHABLE();
552 }
553
554 return returnValue;
555}
556
557TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
558{
559 TConstantUnion returnValue;
560 ASSERT(type == constant.type);
561 switch (type)
562 {
563 case EbtBool:
564 returnValue.setBConst(bConst && constant.bConst);
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 EbtBool:
580 returnValue.setBConst(bConst || constant.bConst);
581 break;
582 default:
583 UNREACHABLE();
584 }
585
586 return returnValue;
587}