blob: 6ef617951b87b8f44f6bf3e507305509aa9d967d [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 Madill596018c2016-09-21 12:57:03 -0400383 returnValue.setIConst(lhs.iConst >> rhs.iConst);
Jamie Madill47cb73a2016-09-09 11:41:44 -0400384 break;
385 case EbtUInt:
Jamie Madill596018c2016-09-21 12:57:03 -0400386 returnValue.setUConst(lhs.uConst >> rhs.uConst);
Jamie Madill47cb73a2016-09-09 11:41:44 -0400387 break;
388 default:
389 UNREACHABLE();
390 }
391
392 return returnValue;
393}
394
Jamie Madill596018c2016-09-21 12:57:03 -0400395// static
396TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,
397 const TConstantUnion &rhs,
398 TDiagnostics *diag,
399 const TSourceLoc &line)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400400{
401 TConstantUnion returnValue;
402 // The signedness of the second parameter might be different, but we
403 // don't care, since the result is undefined if the second parameter is
404 // negative, and aliasing should not be a problem with unions.
Jamie Madill596018c2016-09-21 12:57:03 -0400405 ASSERT((lhs.type == rhs.type) && (lhs.type == EbtInt || lhs.type == EbtUInt));
406 switch (lhs.type)
Jamie Madill47cb73a2016-09-09 11:41:44 -0400407 {
408 case EbtInt:
Jamie Madill596018c2016-09-21 12:57:03 -0400409 returnValue.setIConst(lhs.iConst << rhs.iConst);
Jamie Madill47cb73a2016-09-09 11:41:44 -0400410 break;
411 case EbtUInt:
Jamie Madill596018c2016-09-21 12:57:03 -0400412 returnValue.setUConst(lhs.uConst << rhs.uConst);
Jamie Madill47cb73a2016-09-09 11:41:44 -0400413 break;
414 default:
415 UNREACHABLE();
416 }
417
418 return returnValue;
419}
420
421TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
422{
423 TConstantUnion returnValue;
424 ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
425 switch (type)
426 {
427 case EbtInt:
428 returnValue.setIConst(iConst & constant.iConst);
429 break;
430 case EbtUInt:
431 returnValue.setUConst(uConst & constant.uConst);
432 break;
433 default:
434 UNREACHABLE();
435 }
436
437 return returnValue;
438}
439
440TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
441{
442 TConstantUnion returnValue;
443 ASSERT(type == constant.type);
444 switch (type)
445 {
446 case EbtInt:
447 returnValue.setIConst(iConst | constant.iConst);
448 break;
449 case EbtUInt:
450 returnValue.setUConst(uConst | constant.uConst);
451 break;
452 default:
453 UNREACHABLE();
454 }
455
456 return returnValue;
457}
458
459TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
460{
461 TConstantUnion returnValue;
462 ASSERT(type == constant.type);
463 switch (type)
464 {
465 case EbtInt:
466 returnValue.setIConst(iConst ^ constant.iConst);
467 break;
468 case EbtUInt:
469 returnValue.setUConst(uConst ^ constant.uConst);
470 break;
471 default:
472 UNREACHABLE();
473 }
474
475 return returnValue;
476}
477
478TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
479{
480 TConstantUnion returnValue;
481 ASSERT(type == constant.type);
482 switch (type)
483 {
484 case EbtBool:
485 returnValue.setBConst(bConst && constant.bConst);
486 break;
487 default:
488 UNREACHABLE();
489 }
490
491 return returnValue;
492}
493
494TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
495{
496 TConstantUnion returnValue;
497 ASSERT(type == constant.type);
498 switch (type)
499 {
500 case EbtBool:
501 returnValue.setBConst(bConst || constant.bConst);
502 break;
503 default:
504 UNREACHABLE();
505 }
506
507 return returnValue;
508}