blob: 74bf570a79d8db52949b12ec55a073f189b9a4d6 [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
372TConstantUnion TConstantUnion::operator>>(const TConstantUnion &constant) const
373{
374 TConstantUnion returnValue;
375 ASSERT(type == constant.type);
376 switch (type)
377 {
378 case EbtInt:
379 returnValue.setIConst(iConst >> constant.iConst);
380 break;
381 case EbtUInt:
382 returnValue.setUConst(uConst >> constant.uConst);
383 break;
384 default:
385 UNREACHABLE();
386 }
387
388 return returnValue;
389}
390
391TConstantUnion TConstantUnion::operator<<(const TConstantUnion &constant) const
392{
393 TConstantUnion returnValue;
394 // The signedness of the second parameter might be different, but we
395 // don't care, since the result is undefined if the second parameter is
396 // negative, and aliasing should not be a problem with unions.
397 ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
398 switch (type)
399 {
400 case EbtInt:
401 returnValue.setIConst(iConst << constant.iConst);
402 break;
403 case EbtUInt:
404 returnValue.setUConst(uConst << constant.uConst);
405 break;
406 default:
407 UNREACHABLE();
408 }
409
410 return returnValue;
411}
412
413TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
414{
415 TConstantUnion returnValue;
416 ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
417 switch (type)
418 {
419 case EbtInt:
420 returnValue.setIConst(iConst & constant.iConst);
421 break;
422 case EbtUInt:
423 returnValue.setUConst(uConst & constant.uConst);
424 break;
425 default:
426 UNREACHABLE();
427 }
428
429 return returnValue;
430}
431
432TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
433{
434 TConstantUnion returnValue;
435 ASSERT(type == constant.type);
436 switch (type)
437 {
438 case EbtInt:
439 returnValue.setIConst(iConst | constant.iConst);
440 break;
441 case EbtUInt:
442 returnValue.setUConst(uConst | constant.uConst);
443 break;
444 default:
445 UNREACHABLE();
446 }
447
448 return returnValue;
449}
450
451TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
452{
453 TConstantUnion returnValue;
454 ASSERT(type == constant.type);
455 switch (type)
456 {
457 case EbtInt:
458 returnValue.setIConst(iConst ^ constant.iConst);
459 break;
460 case EbtUInt:
461 returnValue.setUConst(uConst ^ constant.uConst);
462 break;
463 default:
464 UNREACHABLE();
465 }
466
467 return returnValue;
468}
469
470TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
471{
472 TConstantUnion returnValue;
473 ASSERT(type == constant.type);
474 switch (type)
475 {
476 case EbtBool:
477 returnValue.setBConst(bConst && constant.bConst);
478 break;
479 default:
480 UNREACHABLE();
481 }
482
483 return returnValue;
484}
485
486TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
487{
488 TConstantUnion returnValue;
489 ASSERT(type == constant.type);
490 switch (type)
491 {
492 case EbtBool:
493 returnValue.setBConst(bConst || constant.bConst);
494 break;
495 default:
496 UNREACHABLE();
497 }
498
499 return returnValue;
500}