blob: 4547f41cbc74963bd80566e6099e491a71468926 [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;
Jamie Madill596018c2016-09-21 12:57:03 -0400379 ASSERT((lhs.type == rhs.type) && (lhs.type == EbtInt || lhs.type == EbtUInt));
380 switch (lhs.type)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400381 {
382 case EbtInt:
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400383 if (lhs.iConst < 0 || rhs.iConst < 0)
384 {
385 diag->error(line, "Undefined shift", ">>", "");
386 returnValue.setIConst(0);
387 }
388 else
389 {
390 returnValue.setIConst(lhs.iConst >> rhs.iConst);
391 }
Jamie Madill47cb73a2016-09-09 11:41:44 -0400392 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400393
Jamie Madill47cb73a2016-09-09 11:41:44 -0400394 case EbtUInt:
Jamie Madill596018c2016-09-21 12:57:03 -0400395 returnValue.setUConst(lhs.uConst >> rhs.uConst);
Jamie Madill47cb73a2016-09-09 11:41:44 -0400396 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400397
Jamie Madill47cb73a2016-09-09 11:41:44 -0400398 default:
399 UNREACHABLE();
400 }
401
402 return returnValue;
403}
404
Jamie Madill596018c2016-09-21 12:57:03 -0400405// static
406TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,
407 const TConstantUnion &rhs,
408 TDiagnostics *diag,
409 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400410{
411 TConstantUnion returnValue;
412 // The signedness of the second parameter might be different, but we
413 // don't care, since the result is undefined if the second parameter is
414 // negative, and aliasing should not be a problem with unions.
Jamie Madill596018c2016-09-21 12:57:03 -0400415 ASSERT((lhs.type == rhs.type) && (lhs.type == EbtInt || lhs.type == EbtUInt));
416 switch (lhs.type)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400417 {
418 case EbtInt:
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400419 if (lhs.iConst < 0 || rhs.iConst < 0)
420 {
421 diag->error(line, "Undefined shift", "<<", "");
422 returnValue.setIConst(0);
423 }
424 else
425 {
426 returnValue.setIConst(lhs.iConst << rhs.iConst);
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 case EbtUInt:
Jamie Madill596018c2016-09-21 12:57:03 -0400431 returnValue.setUConst(lhs.uConst << rhs.uConst);
Jamie Madill47cb73a2016-09-09 11:41:44 -0400432 break;
Jamie Madill44ebf6b2016-09-22 13:00:02 -0400433
Jamie Madill47cb73a2016-09-09 11:41:44 -0400434 default:
435 UNREACHABLE();
436 }
437
438 return returnValue;
439}
440
441TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
442{
443 TConstantUnion returnValue;
444 ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
445 switch (type)
446 {
447 case EbtInt:
448 returnValue.setIConst(iConst & constant.iConst);
449 break;
450 case EbtUInt:
451 returnValue.setUConst(uConst & constant.uConst);
452 break;
453 default:
454 UNREACHABLE();
455 }
456
457 return returnValue;
458}
459
460TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
461{
462 TConstantUnion returnValue;
463 ASSERT(type == constant.type);
464 switch (type)
465 {
466 case EbtInt:
467 returnValue.setIConst(iConst | constant.iConst);
468 break;
469 case EbtUInt:
470 returnValue.setUConst(uConst | constant.uConst);
471 break;
472 default:
473 UNREACHABLE();
474 }
475
476 return returnValue;
477}
478
479TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
480{
481 TConstantUnion returnValue;
482 ASSERT(type == constant.type);
483 switch (type)
484 {
485 case EbtInt:
486 returnValue.setIConst(iConst ^ constant.iConst);
487 break;
488 case EbtUInt:
489 returnValue.setUConst(uConst ^ constant.uConst);
490 break;
491 default:
492 UNREACHABLE();
493 }
494
495 return returnValue;
496}
497
498TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
499{
500 TConstantUnion returnValue;
501 ASSERT(type == constant.type);
502 switch (type)
503 {
504 case EbtBool:
505 returnValue.setBConst(bConst && constant.bConst);
506 break;
507 default:
508 UNREACHABLE();
509 }
510
511 return returnValue;
512}
513
514TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
515{
516 TConstantUnion returnValue;
517 ASSERT(type == constant.type);
518 switch (type)
519 {
520 case EbtBool:
521 returnValue.setBConst(bConst || constant.bConst);
522 break;
523 default:
524 UNREACHABLE();
525 }
526
527 return returnValue;
528}