xref: /aosp_15_r20/external/emboss/compiler/front_end/expression_bounds_test.py (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1# Copyright 2019 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Tests for expression_bounds."""
16
17import unittest
18from compiler.front_end import expression_bounds
19from compiler.front_end import glue
20from compiler.util import test_util
21
22
23class ComputeConstantsTest(unittest.TestCase):
24
25  def _make_ir(self, emb_text):
26    ir, unused_debug_info, errors = glue.parse_emboss_file(
27        "m.emb",
28        test_util.dict_file_reader({"m.emb": emb_text}),
29        stop_before_step="compute_constants")
30    assert not errors, errors
31    return ir
32
33  def test_constant_integer(self):
34    ir = self._make_ir("struct Foo:\n"
35                       "  10 [+1]  UInt  x\n")
36    self.assertEqual([], expression_bounds.compute_constants(ir))
37    start = ir.module[0].type[0].structure.field[0].location.start
38    self.assertEqual("10", start.type.integer.minimum_value)
39    self.assertEqual("10", start.type.integer.maximum_value)
40    self.assertEqual("10", start.type.integer.modular_value)
41    self.assertEqual("infinity", start.type.integer.modulus)
42
43  def test_boolean_constant(self):
44    ir = self._make_ir("struct Foo:\n"
45                       "  if true:\n"
46                       "    0 [+1]  UInt  x\n")
47    self.assertEqual([], expression_bounds.compute_constants(ir))
48    expression = ir.module[0].type[0].structure.field[0].existence_condition
49    self.assertTrue(expression.type.boolean.HasField("value"))
50    self.assertTrue(expression.type.boolean.value)
51
52  def test_constant_equality(self):
53    ir = self._make_ir("struct Foo:\n"
54                       "  if 5 == 5:\n"
55                       "    0 [+1]  UInt  x\n"
56                       "  if 5 == 6:\n"
57                       "    0 [+1]  UInt  y\n")
58    self.assertEqual([], expression_bounds.compute_constants(ir))
59    structure = ir.module[0].type[0].structure
60    true_condition = structure.field[0].existence_condition
61    false_condition = structure.field[1].existence_condition
62    self.assertTrue(true_condition.type.boolean.HasField("value"))
63    self.assertTrue(true_condition.type.boolean.value)
64    self.assertTrue(false_condition.type.boolean.HasField("value"))
65    self.assertFalse(false_condition.type.boolean.value)
66
67  def test_constant_inequality(self):
68    ir = self._make_ir("struct Foo:\n"
69                       "  if 5 != 5:\n"
70                       "    0 [+1]  UInt  x\n"
71                       "  if 5 != 6:\n"
72                       "    0 [+1]  UInt  y\n")
73    self.assertEqual([], expression_bounds.compute_constants(ir))
74    structure = ir.module[0].type[0].structure
75    false_condition = structure.field[0].existence_condition
76    true_condition = structure.field[1].existence_condition
77    self.assertTrue(false_condition.type.boolean.HasField("value"))
78    self.assertFalse(false_condition.type.boolean.value)
79    self.assertTrue(true_condition.type.boolean.HasField("value"))
80    self.assertTrue(true_condition.type.boolean.value)
81
82  def test_constant_less_than(self):
83    ir = self._make_ir("struct Foo:\n"
84                       "  if 5 < 4:\n"
85                       "    0 [+1]  UInt  x\n"
86                       "  if 5 < 5:\n"
87                       "    0 [+1]  UInt  y\n"
88                       "  if 5 < 6:\n"
89                       "    0 [+1]  UInt  z\n")
90    self.assertEqual([], expression_bounds.compute_constants(ir))
91    structure = ir.module[0].type[0].structure
92    greater_than_condition = structure.field[0].existence_condition
93    equal_condition = structure.field[1].existence_condition
94    less_than_condition = structure.field[2].existence_condition
95    self.assertTrue(greater_than_condition.type.boolean.HasField("value"))
96    self.assertFalse(greater_than_condition.type.boolean.value)
97    self.assertTrue(equal_condition.type.boolean.HasField("value"))
98    self.assertFalse(equal_condition.type.boolean.value)
99    self.assertTrue(less_than_condition.type.boolean.HasField("value"))
100    self.assertTrue(less_than_condition.type.boolean.value)
101
102  def test_constant_less_than_or_equal(self):
103    ir = self._make_ir("struct Foo:\n"
104                       "  if 5 <= 4:\n"
105                       "    0 [+1]  UInt  x\n"
106                       "  if 5 <= 5:\n"
107                       "    0 [+1]  UInt  y\n"
108                       "  if 5 <= 6:\n"
109                       "    0 [+1]  UInt  z\n")
110    self.assertEqual([], expression_bounds.compute_constants(ir))
111    structure = ir.module[0].type[0].structure
112    greater_than_condition = structure.field[0].existence_condition
113    equal_condition = structure.field[1].existence_condition
114    less_than_condition = structure.field[2].existence_condition
115    self.assertTrue(greater_than_condition.type.boolean.HasField("value"))
116    self.assertFalse(greater_than_condition.type.boolean.value)
117    self.assertTrue(equal_condition.type.boolean.HasField("value"))
118    self.assertTrue(equal_condition.type.boolean.value)
119    self.assertTrue(less_than_condition.type.boolean.HasField("value"))
120    self.assertTrue(less_than_condition.type.boolean.value)
121
122  def test_constant_greater_than(self):
123    ir = self._make_ir("struct Foo:\n"
124                       "  if 5 > 4:\n"
125                       "    0 [+1]  UInt  x\n"
126                       "  if 5 > 5:\n"
127                       "    0 [+1]  UInt  y\n"
128                       "  if 5 > 6:\n"
129                       "    0 [+1]  UInt  z\n")
130    self.assertEqual([], expression_bounds.compute_constants(ir))
131    structure = ir.module[0].type[0].structure
132    greater_than_condition = structure.field[0].existence_condition
133    equal_condition = structure.field[1].existence_condition
134    less_than_condition = structure.field[2].existence_condition
135    self.assertTrue(greater_than_condition.type.boolean.HasField("value"))
136    self.assertTrue(greater_than_condition.type.boolean.value)
137    self.assertTrue(equal_condition.type.boolean.HasField("value"))
138    self.assertFalse(equal_condition.type.boolean.value)
139    self.assertTrue(less_than_condition.type.boolean.HasField("value"))
140    self.assertFalse(less_than_condition.type.boolean.value)
141
142  def test_constant_greater_than_or_equal(self):
143    ir = self._make_ir("struct Foo:\n"
144                       "  if 5 >= 4:\n"
145                       "    0 [+1]  UInt  x\n"
146                       "  if 5 >= 5:\n"
147                       "    0 [+1]  UInt  y\n"
148                       "  if 5 >= 6:\n"
149                       "    0 [+1]  UInt  z\n")
150    self.assertEqual([], expression_bounds.compute_constants(ir))
151    structure = ir.module[0].type[0].structure
152    greater_than_condition = structure.field[0].existence_condition
153    equal_condition = structure.field[1].existence_condition
154    less_than_condition = structure.field[2].existence_condition
155    self.assertTrue(greater_than_condition.type.boolean.HasField("value"))
156    self.assertTrue(greater_than_condition.type.boolean.value)
157    self.assertTrue(equal_condition.type.boolean.HasField("value"))
158    self.assertTrue(equal_condition.type.boolean.value)
159    self.assertTrue(less_than_condition.type.boolean.HasField("value"))
160    self.assertFalse(less_than_condition.type.boolean.value)
161
162  def test_constant_and(self):
163    ir = self._make_ir("struct Foo:\n"
164                       "  if false && false:\n"
165                       "    0 [+1]  UInt  x\n"
166                       "  if true && false:\n"
167                       "    0 [+1]  UInt  y\n"
168                       "  if false && true:\n"
169                       "    0 [+1]  UInt  z\n"
170                       "  if true && true:\n"
171                       "    0 [+1]  UInt  w\n")
172    self.assertEqual([], expression_bounds.compute_constants(ir))
173    structure = ir.module[0].type[0].structure
174    false_false_condition = structure.field[0].existence_condition
175    true_false_condition = structure.field[1].existence_condition
176    false_true_condition = structure.field[2].existence_condition
177    true_true_condition = structure.field[3].existence_condition
178    self.assertTrue(false_false_condition.type.boolean.HasField("value"))
179    self.assertFalse(false_false_condition.type.boolean.value)
180    self.assertTrue(true_false_condition.type.boolean.HasField("value"))
181    self.assertFalse(true_false_condition.type.boolean.value)
182    self.assertTrue(false_true_condition.type.boolean.HasField("value"))
183    self.assertFalse(false_true_condition.type.boolean.value)
184    self.assertTrue(true_true_condition.type.boolean.HasField("value"))
185    self.assertTrue(true_true_condition.type.boolean.value)
186
187  def test_constant_or(self):
188    ir = self._make_ir("struct Foo:\n"
189                       "  if false || false:\n"
190                       "    0 [+1]  UInt  x\n"
191                       "  if true || false:\n"
192                       "    0 [+1]  UInt  y\n"
193                       "  if false || true:\n"
194                       "    0 [+1]  UInt  z\n"
195                       "  if true || true:\n"
196                       "    0 [+1]  UInt  w\n")
197    self.assertEqual([], expression_bounds.compute_constants(ir))
198    structure = ir.module[0].type[0].structure
199    false_false_condition = structure.field[0].existence_condition
200    true_false_condition = structure.field[1].existence_condition
201    false_true_condition = structure.field[2].existence_condition
202    true_true_condition = structure.field[3].existence_condition
203    self.assertTrue(false_false_condition.type.boolean.HasField("value"))
204    self.assertFalse(false_false_condition.type.boolean.value)
205    self.assertTrue(true_false_condition.type.boolean.HasField("value"))
206    self.assertTrue(true_false_condition.type.boolean.value)
207    self.assertTrue(false_true_condition.type.boolean.HasField("value"))
208    self.assertTrue(false_true_condition.type.boolean.value)
209    self.assertTrue(true_true_condition.type.boolean.HasField("value"))
210    self.assertTrue(true_true_condition.type.boolean.value)
211
212  def test_enum_constant(self):
213    ir = self._make_ir("struct Foo:\n"
214                       "  if Bar.QUX == Bar.QUX:\n"
215                       "    0 [+1]  Bar  x\n"
216                       "enum Bar:\n"
217                       "  QUX = 12\n")
218    self.assertEqual([], expression_bounds.compute_constants(ir))
219    condition = ir.module[0].type[0].structure.field[0].existence_condition
220    left = condition.function.args[0]
221    self.assertEqual("12", left.type.enumeration.value)
222
223  def test_non_constant_field_reference(self):
224    ir = self._make_ir("struct Foo:\n"
225                       "  y [+1]  UInt  x\n"
226                       "  0 [+1]  UInt  y\n")
227    self.assertEqual([], expression_bounds.compute_constants(ir))
228    start = ir.module[0].type[0].structure.field[0].location.start
229    self.assertEqual("0", start.type.integer.minimum_value)
230    self.assertEqual("255", start.type.integer.maximum_value)
231    self.assertEqual("0", start.type.integer.modular_value)
232    self.assertEqual("1", start.type.integer.modulus)
233
234  def test_field_reference_bounds_are_uncomputable(self):
235    # Variable-sized UInt/Int/Bcd should not cause an error here: they are
236    # handled in the constraints pass.
237    ir = self._make_ir("struct Foo:\n"
238                       "  0 [+1]  UInt  x\n"
239                       "  0 [+x]  UInt  y\n"
240                       "  y [+1]  UInt  z\n")
241    self.assertEqual([], expression_bounds.compute_constants(ir))
242
243  def test_field_references_references_bounds_are_uncomputable(self):
244    ir = self._make_ir("struct Foo:\n"
245                       "  0 [+1]  UInt  x\n"
246                       "  0 [+x]  UInt  y\n"
247                       "  0 [+y]  UInt  z\n"
248                       "  z [+1]  UInt  q\n")
249    self.assertEqual([], expression_bounds.compute_constants(ir))
250
251  def test_non_constant_equality(self):
252    ir = self._make_ir("struct Foo:\n"
253                       "  if 5 == y:\n"
254                       "    0 [+1]  UInt  x\n"
255                       "  0 [+1]  UInt  y\n")
256    self.assertEqual([], expression_bounds.compute_constants(ir))
257    structure = ir.module[0].type[0].structure
258    condition = structure.field[0].existence_condition
259    self.assertFalse(condition.type.boolean.HasField("value"))
260
261  def test_constant_addition(self):
262    ir = self._make_ir("struct Foo:\n"
263                       "  7+5 [+1]  UInt  x\n")
264    self.assertEqual([], expression_bounds.compute_constants(ir))
265    start = ir.module[0].type[0].structure.field[0].location.start
266    self.assertEqual("12", start.type.integer.minimum_value)
267    self.assertEqual("12", start.type.integer.maximum_value)
268    self.assertEqual("12", start.type.integer.modular_value)
269    self.assertEqual("infinity", start.type.integer.modulus)
270    self.assertEqual("7", start.function.args[0].type.integer.minimum_value)
271    self.assertEqual("7", start.function.args[0].type.integer.maximum_value)
272    self.assertEqual("7", start.function.args[0].type.integer.modular_value)
273    self.assertEqual("infinity", start.type.integer.modulus)
274    self.assertEqual("5", start.function.args[1].type.integer.minimum_value)
275    self.assertEqual("5", start.function.args[1].type.integer.maximum_value)
276    self.assertEqual("5", start.function.args[1].type.integer.modular_value)
277    self.assertEqual("infinity", start.type.integer.modulus)
278
279  def test_constant_subtraction(self):
280    ir = self._make_ir("struct Foo:\n"
281                       "  7-5 [+1]  UInt  x\n")
282    self.assertEqual([], expression_bounds.compute_constants(ir))
283    start = ir.module[0].type[0].structure.field[0].location.start
284    self.assertEqual("2", start.type.integer.minimum_value)
285    self.assertEqual("2", start.type.integer.maximum_value)
286    self.assertEqual("2", start.type.integer.modular_value)
287    self.assertEqual("infinity", start.type.integer.modulus)
288    self.assertEqual("7", start.function.args[0].type.integer.minimum_value)
289    self.assertEqual("7", start.function.args[0].type.integer.maximum_value)
290    self.assertEqual("7", start.function.args[0].type.integer.modular_value)
291    self.assertEqual("infinity", start.type.integer.modulus)
292    self.assertEqual("5", start.function.args[1].type.integer.minimum_value)
293    self.assertEqual("5", start.function.args[1].type.integer.maximum_value)
294    self.assertEqual("5", start.function.args[1].type.integer.modular_value)
295    self.assertEqual("infinity", start.type.integer.modulus)
296
297  def test_constant_multiplication(self):
298    ir = self._make_ir("struct Foo:\n"
299                       "  7*5 [+1]  UInt  x\n")
300    self.assertEqual([], expression_bounds.compute_constants(ir))
301    start = ir.module[0].type[0].structure.field[0].location.start
302    self.assertEqual("35", start.type.integer.minimum_value)
303    self.assertEqual("35", start.type.integer.maximum_value)
304    self.assertEqual("35", start.type.integer.modular_value)
305    self.assertEqual("infinity", start.type.integer.modulus)
306    self.assertEqual("7", start.function.args[0].type.integer.minimum_value)
307    self.assertEqual("7", start.function.args[0].type.integer.maximum_value)
308    self.assertEqual("7", start.function.args[0].type.integer.modular_value)
309    self.assertEqual("infinity", start.type.integer.modulus)
310    self.assertEqual("5", start.function.args[1].type.integer.minimum_value)
311    self.assertEqual("5", start.function.args[1].type.integer.maximum_value)
312    self.assertEqual("5", start.function.args[1].type.integer.modular_value)
313    self.assertEqual("infinity", start.type.integer.modulus)
314
315  def test_nested_constant_expression(self):
316    ir = self._make_ir("struct Foo:\n"
317                       "  if 7*(3+1) == 28:\n"
318                       "    0 [+1]  UInt  x\n")
319    self.assertEqual([], expression_bounds.compute_constants(ir))
320    condition = ir.module[0].type[0].structure.field[0].existence_condition
321    self.assertTrue(condition.type.boolean.value)
322    condition_left = condition.function.args[0]
323    self.assertEqual("28", condition_left.type.integer.minimum_value)
324    self.assertEqual("28", condition_left.type.integer.maximum_value)
325    self.assertEqual("28", condition_left.type.integer.modular_value)
326    self.assertEqual("infinity", condition_left.type.integer.modulus)
327    condition_left_left = condition_left.function.args[0]
328    self.assertEqual("7", condition_left_left.type.integer.minimum_value)
329    self.assertEqual("7", condition_left_left.type.integer.maximum_value)
330    self.assertEqual("7", condition_left_left.type.integer.modular_value)
331    self.assertEqual("infinity", condition_left_left.type.integer.modulus)
332    condition_left_right = condition_left.function.args[1]
333    self.assertEqual("4", condition_left_right.type.integer.minimum_value)
334    self.assertEqual("4", condition_left_right.type.integer.maximum_value)
335    self.assertEqual("4", condition_left_right.type.integer.modular_value)
336    self.assertEqual("infinity", condition_left_right.type.integer.modulus)
337    condition_left_right_left = condition_left_right.function.args[0]
338    self.assertEqual("3", condition_left_right_left.type.integer.minimum_value)
339    self.assertEqual("3", condition_left_right_left.type.integer.maximum_value)
340    self.assertEqual("3", condition_left_right_left.type.integer.modular_value)
341    self.assertEqual("infinity", condition_left_right_left.type.integer.modulus)
342    condition_left_right_right = condition_left_right.function.args[1]
343    self.assertEqual("1", condition_left_right_right.type.integer.minimum_value)
344    self.assertEqual("1", condition_left_right_right.type.integer.maximum_value)
345    self.assertEqual("1", condition_left_right_right.type.integer.modular_value)
346    self.assertEqual("infinity",
347                     condition_left_right_right.type.integer.modulus)
348
349  def test_constant_plus_non_constant(self):
350    ir = self._make_ir("struct Foo:\n"
351                       "  0       [+1]  UInt  x\n"
352                       "  5+(4*x) [+1]  UInt  y\n")
353    self.assertEqual([], expression_bounds.compute_constants(ir))
354    y_start = ir.module[0].type[0].structure.field[1].location.start
355    self.assertEqual("4", y_start.type.integer.modulus)
356    self.assertEqual("1", y_start.type.integer.modular_value)
357    self.assertEqual("5", y_start.type.integer.minimum_value)
358    self.assertEqual("1025", y_start.type.integer.maximum_value)
359
360  def test_constant_minus_non_constant(self):
361    ir = self._make_ir("struct Foo:\n"
362                       "  0       [+1]  UInt  x\n"
363                       "  5-(4*x) [+1]  UInt  y\n")
364    self.assertEqual([], expression_bounds.compute_constants(ir))
365    y_start = ir.module[0].type[0].structure.field[1].location.start
366    self.assertEqual("4", y_start.type.integer.modulus)
367    self.assertEqual("1", y_start.type.integer.modular_value)
368    self.assertEqual("-1015", y_start.type.integer.minimum_value)
369    self.assertEqual("5", y_start.type.integer.maximum_value)
370
371  def test_non_constant_minus_constant(self):
372    ir = self._make_ir("struct Foo:\n"
373                       "  0       [+1]  UInt  x\n"
374                       "  (4*x)-5 [+1]  UInt  y\n")
375    self.assertEqual([], expression_bounds.compute_constants(ir))
376    y_start = ir.module[0].type[0].structure.field[1].location.start
377    self.assertEqual(str((4 * 0) - 5), y_start.type.integer.minimum_value)
378    self.assertEqual(str((4 * 255) - 5), y_start.type.integer.maximum_value)
379    self.assertEqual("4", y_start.type.integer.modulus)
380    self.assertEqual("3", y_start.type.integer.modular_value)
381
382  def test_non_constant_plus_non_constant(self):
383    ir = self._make_ir("struct Foo:\n"
384                       "  0             [+1]  UInt  x\n"
385                       "  1             [+1]  UInt  y\n"
386                       "  (4*x)+(6*y+3) [+1]  UInt  z\n")
387    self.assertEqual([], expression_bounds.compute_constants(ir))
388    z_start = ir.module[0].type[0].structure.field[2].location.start
389    self.assertEqual("3", z_start.type.integer.minimum_value)
390    self.assertEqual(str(4 * 255 + 6 * 255 + 3),
391                     z_start.type.integer.maximum_value)
392    self.assertEqual("2", z_start.type.integer.modulus)
393    self.assertEqual("1", z_start.type.integer.modular_value)
394
395  def test_non_constant_minus_non_constant(self):
396    ir = self._make_ir("struct Foo:\n"
397                       "  0            [+1]  UInt  x\n"
398                       "  1            [+1]  UInt  y\n"
399                       "  (x*3)-(y*3)  [+1]  UInt  z\n")
400    self.assertEqual([], expression_bounds.compute_constants(ir))
401    z_start = ir.module[0].type[0].structure.field[2].location.start
402    self.assertEqual("3", z_start.type.integer.modulus)
403    self.assertEqual("0", z_start.type.integer.modular_value)
404    self.assertEqual(str(-3 * 255), z_start.type.integer.minimum_value)
405    self.assertEqual(str(3 * 255), z_start.type.integer.maximum_value)
406
407  def test_non_constant_times_constant(self):
408    ir = self._make_ir("struct Foo:\n"
409                       "  0         [+1]  UInt  x\n"
410                       "  (4*x+1)*5 [+1]  UInt  y\n")
411    self.assertEqual([], expression_bounds.compute_constants(ir))
412    y_start = ir.module[0].type[0].structure.field[1].location.start
413    self.assertEqual("20", y_start.type.integer.modulus)
414    self.assertEqual("5", y_start.type.integer.modular_value)
415    self.assertEqual("5", y_start.type.integer.minimum_value)
416    self.assertEqual(str((4 * 255 + 1) * 5), y_start.type.integer.maximum_value)
417
418  def test_non_constant_times_negative_constant(self):
419    ir = self._make_ir("struct Foo:\n"
420                       "  0          [+1]  UInt  x\n"
421                       "  (4*x+1)*-5 [+1]  UInt  y\n")
422    self.assertEqual([], expression_bounds.compute_constants(ir))
423    y_start = ir.module[0].type[0].structure.field[1].location.start
424    self.assertEqual("20", y_start.type.integer.modulus)
425    self.assertEqual("15", y_start.type.integer.modular_value)
426    self.assertEqual(str((4 * 255 + 1) * -5),
427                     y_start.type.integer.minimum_value)
428    self.assertEqual("-5", y_start.type.integer.maximum_value)
429
430  def test_non_constant_times_zero(self):
431    ir = self._make_ir("struct Foo:\n"
432                       "  0         [+1]  UInt  x\n"
433                       "  (4*x+1)*0 [+1]  UInt  y\n")
434    self.assertEqual([], expression_bounds.compute_constants(ir))
435    y_start = ir.module[0].type[0].structure.field[1].location.start
436    self.assertEqual("infinity", y_start.type.integer.modulus)
437    self.assertEqual("0", y_start.type.integer.modular_value)
438    self.assertEqual("0", y_start.type.integer.minimum_value)
439    self.assertEqual("0", y_start.type.integer.maximum_value)
440
441  def test_non_constant_times_non_constant_shared_modulus(self):
442    ir = self._make_ir("struct Foo:\n"
443                       "  0               [+1]  UInt  x\n"
444                       "  1               [+1]  UInt  y\n"
445                       "  (4*x+3)*(4*y+3) [+1]  UInt  z\n")
446    self.assertEqual([], expression_bounds.compute_constants(ir))
447    z_start = ir.module[0].type[0].structure.field[2].location.start
448    self.assertEqual("4", z_start.type.integer.modulus)
449    self.assertEqual("1", z_start.type.integer.modular_value)
450    self.assertEqual("9", z_start.type.integer.minimum_value)
451    self.assertEqual(str((4 * 255 + 3)**2), z_start.type.integer.maximum_value)
452
453  def test_non_constant_times_non_constant_congruent_to_zero(self):
454    ir = self._make_ir("struct Foo:\n"
455                       "  0           [+1]  UInt  x\n"
456                       "  1           [+1]  UInt  y\n"
457                       "  (4*x)*(4*y) [+1]  UInt  z\n")
458    self.assertEqual([], expression_bounds.compute_constants(ir))
459    z_start = ir.module[0].type[0].structure.field[2].location.start
460    self.assertEqual("16", z_start.type.integer.modulus)
461    self.assertEqual("0", z_start.type.integer.modular_value)
462    self.assertEqual("0", z_start.type.integer.minimum_value)
463    self.assertEqual(str((4 * 255)**2), z_start.type.integer.maximum_value)
464
465  def test_non_constant_times_non_constant_partially_shared_modulus(self):
466    ir = self._make_ir("struct Foo:\n"
467                       "  0               [+1]  UInt  x\n"
468                       "  1               [+1]  UInt  y\n"
469                       "  (4*x+3)*(8*y+3) [+1]  UInt  z\n")
470    self.assertEqual([], expression_bounds.compute_constants(ir))
471    z_start = ir.module[0].type[0].structure.field[2].location.start
472    self.assertEqual("4", z_start.type.integer.modulus)
473    self.assertEqual("1", z_start.type.integer.modular_value)
474    self.assertEqual("9", z_start.type.integer.minimum_value)
475    self.assertEqual(str((4 * 255 + 3) * (8 * 255 + 3)),
476                     z_start.type.integer.maximum_value)
477
478  def test_non_constant_times_non_constant_full_complexity(self):
479    ir = self._make_ir("struct Foo:\n"
480                       "  0                  [+1]  UInt  x\n"
481                       "  1                  [+1]  UInt  y\n"
482                       "  (12*x+9)*(40*y+15) [+1]  UInt  z\n")
483    self.assertEqual([], expression_bounds.compute_constants(ir))
484    z_start = ir.module[0].type[0].structure.field[2].location.start
485    self.assertEqual("60", z_start.type.integer.modulus)
486    self.assertEqual("15", z_start.type.integer.modular_value)
487    self.assertEqual(str(9 * 15), z_start.type.integer.minimum_value)
488    self.assertEqual(str((12 * 255 + 9) * (40 * 255 + 15)),
489                     z_start.type.integer.maximum_value)
490
491  def test_signed_non_constant_times_signed_non_constant_full_complexity(self):
492    ir = self._make_ir("struct Foo:\n"
493                       "  0                  [+1]  Int  x\n"
494                       "  1                  [+1]  Int  y\n"
495                       "  (12*x+9)*(40*y+15) [+1]  Int  z\n")
496    self.assertEqual([], expression_bounds.compute_constants(ir))
497    z_start = ir.module[0].type[0].structure.field[2].location.start
498    self.assertEqual("60", z_start.type.integer.modulus)
499    self.assertEqual("15", z_start.type.integer.modular_value)
500    # Max x/min y is slightly lower than min x/max y (-7825965 vs -7780065).
501    self.assertEqual(str((12 * 127 + 9) * (40 * -128 + 15)),
502                     z_start.type.integer.minimum_value)
503    # Max x/max y is slightly higher than min x/min y (7810635 vs 7795335).
504    self.assertEqual(str((12 * 127 + 9) * (40 * 127 + 15)),
505                     z_start.type.integer.maximum_value)
506
507  def test_non_constant_times_non_constant_flipped_min_max(self):
508    ir = self._make_ir("struct Foo:\n"
509                       "  0             [+1]  UInt  x\n"
510                       "  1             [+1]  UInt  y\n"
511                       "  (-x*3)*(y*3)  [+1]  UInt  z\n")
512    self.assertEqual([], expression_bounds.compute_constants(ir))
513    z_start = ir.module[0].type[0].structure.field[2].location.start
514    self.assertEqual("9", z_start.type.integer.modulus)
515    self.assertEqual("0", z_start.type.integer.modular_value)
516    self.assertEqual(str(-((3 * 255)**2)), z_start.type.integer.minimum_value)
517    self.assertEqual("0", z_start.type.integer.maximum_value)
518
519  # Currently, only `$static_size_in_bits` has an infinite bound, so all of the
520  # examples below use `$static_size_in_bits`.  Unfortunately, this also means
521  # that these tests rely on the fact that Emboss doesn't try to do any term
522  # rewriting or smart correlation between the arguments of various operators:
523  # for example, several tests rely on `$static_size_in_bits -
524  # $static_size_in_bits` having the range `-infinity` to `infinity`, when a
525  # trivial term rewrite would turn that expression into `0`.
526  #
527  # Unbounded expressions are only allowed at compile-time anyway, so these
528  # tests cover some fairly unlikely uses of the Emboss expression language.
529  def test_unbounded_plus_constant(self):
530    ir = self._make_ir("external Foo:\n"
531                       "  [requires: $static_size_in_bits + 2 > 0]\n")
532    self.assertEqual([], expression_bounds.compute_constants(ir))
533    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
534    self.assertEqual("1", expr.type.integer.modulus)
535    self.assertEqual("0", expr.type.integer.modular_value)
536    self.assertEqual("2", expr.type.integer.minimum_value)
537    self.assertEqual("infinity", expr.type.integer.maximum_value)
538
539  def test_negative_unbounded_plus_constant(self):
540    ir = self._make_ir("external Foo:\n"
541                       "  [requires: -$static_size_in_bits + 2 > 0]\n")
542    self.assertEqual([], expression_bounds.compute_constants(ir))
543    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
544    self.assertEqual("1", expr.type.integer.modulus)
545    self.assertEqual("0", expr.type.integer.modular_value)
546    self.assertEqual("-infinity", expr.type.integer.minimum_value)
547    self.assertEqual("2", expr.type.integer.maximum_value)
548
549  def test_negative_unbounded_plus_unbounded(self):
550    ir = self._make_ir(
551        "external Foo:\n"
552        "  [requires: -$static_size_in_bits + $static_size_in_bits > 0]\n")
553    self.assertEqual([], expression_bounds.compute_constants(ir))
554    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
555    self.assertEqual("1", expr.type.integer.modulus)
556    self.assertEqual("0", expr.type.integer.modular_value)
557    self.assertEqual("-infinity", expr.type.integer.minimum_value)
558    self.assertEqual("infinity", expr.type.integer.maximum_value)
559
560  def test_unbounded_minus_unbounded(self):
561    ir = self._make_ir(
562        "external Foo:\n"
563        "  [requires: $static_size_in_bits - $static_size_in_bits > 0]\n")
564    self.assertEqual([], expression_bounds.compute_constants(ir))
565    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
566    self.assertEqual("1", expr.type.integer.modulus)
567    self.assertEqual("0", expr.type.integer.modular_value)
568    self.assertEqual("-infinity", expr.type.integer.minimum_value)
569    self.assertEqual("infinity", expr.type.integer.maximum_value)
570
571  def test_unbounded_minus_negative_unbounded(self):
572    ir = self._make_ir(
573        "external Foo:\n"
574        "  [requires: $static_size_in_bits - -$static_size_in_bits > 0]\n")
575    self.assertEqual([], expression_bounds.compute_constants(ir))
576    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
577    self.assertEqual("1", expr.type.integer.modulus)
578    self.assertEqual("0", expr.type.integer.modular_value)
579    self.assertEqual("0", expr.type.integer.minimum_value)
580    self.assertEqual("infinity", expr.type.integer.maximum_value)
581
582  def test_unbounded_times_constant(self):
583    ir = self._make_ir("external Foo:\n"
584                       "  [requires: ($static_size_in_bits + 1) * 2 > 0]\n")
585    self.assertEqual([], expression_bounds.compute_constants(ir))
586    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
587    self.assertEqual("2", expr.type.integer.modulus)
588    self.assertEqual("0", expr.type.integer.modular_value)
589    self.assertEqual("2", expr.type.integer.minimum_value)
590    self.assertEqual("infinity", expr.type.integer.maximum_value)
591
592  def test_unbounded_times_negative_constant(self):
593    ir = self._make_ir("external Foo:\n"
594                       "  [requires: ($static_size_in_bits + 1) * -2 > 0]\n")
595    self.assertEqual([], expression_bounds.compute_constants(ir))
596    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
597    self.assertEqual("2", expr.type.integer.modulus)
598    self.assertEqual("0", expr.type.integer.modular_value)
599    self.assertEqual("-infinity", expr.type.integer.minimum_value)
600    self.assertEqual("-2", expr.type.integer.maximum_value)
601
602  def test_unbounded_times_negative_zero(self):
603    ir = self._make_ir("external Foo:\n"
604                       "  [requires: ($static_size_in_bits + 1) * 0 > 0]\n")
605    self.assertEqual([], expression_bounds.compute_constants(ir))
606    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
607    self.assertEqual("infinity", expr.type.integer.modulus)
608    self.assertEqual("0", expr.type.integer.modular_value)
609    self.assertEqual("0", expr.type.integer.minimum_value)
610    self.assertEqual("0", expr.type.integer.maximum_value)
611
612  def test_negative_unbounded_times_constant(self):
613    ir = self._make_ir("external Foo:\n"
614                       "  [requires: (-$static_size_in_bits + 1) * 2 > 0]\n")
615    self.assertEqual([], expression_bounds.compute_constants(ir))
616    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
617    self.assertEqual("2", expr.type.integer.modulus)
618    self.assertEqual("0", expr.type.integer.modular_value)
619    self.assertEqual("-infinity", expr.type.integer.minimum_value)
620    self.assertEqual("2", expr.type.integer.maximum_value)
621
622  def test_double_unbounded_minus_unbounded(self):
623    ir = self._make_ir(
624        "external Foo:\n"
625        "  [requires: 2 * $static_size_in_bits - $static_size_in_bits > 0]\n")
626    self.assertEqual([], expression_bounds.compute_constants(ir))
627    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
628    self.assertEqual("1", expr.type.integer.modulus)
629    self.assertEqual("0", expr.type.integer.modular_value)
630    self.assertEqual("-infinity", expr.type.integer.minimum_value)
631    self.assertEqual("infinity", expr.type.integer.maximum_value)
632
633  def test_double_unbounded_times_negative_unbounded(self):
634    ir = self._make_ir(
635        "external Foo:\n"
636        "  [requires: 2 * $static_size_in_bits * -$static_size_in_bits > 0]\n")
637    self.assertEqual([], expression_bounds.compute_constants(ir))
638    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
639    self.assertEqual("2", expr.type.integer.modulus)
640    self.assertEqual("0", expr.type.integer.modular_value)
641    self.assertEqual("-infinity", expr.type.integer.minimum_value)
642    self.assertEqual("0", expr.type.integer.maximum_value)
643
644  def test_upper_bound_of_field(self):
645    ir = self._make_ir("struct Foo:\n"
646                       "  0 [+1]  Int  x\n"
647                       "  let u = $upper_bound(x)\n")
648    self.assertEqual([], expression_bounds.compute_constants(ir))
649    u_type = ir.module[0].type[0].structure.field[1].read_transform.type
650    self.assertEqual("infinity", u_type.integer.modulus)
651    self.assertEqual("127", u_type.integer.maximum_value)
652    self.assertEqual("127", u_type.integer.minimum_value)
653    self.assertEqual("127", u_type.integer.modular_value)
654
655  def test_lower_bound_of_field(self):
656    ir = self._make_ir("struct Foo:\n"
657                       "  0 [+1]  Int  x\n"
658                       "  let l = $lower_bound(x)\n")
659    self.assertEqual([], expression_bounds.compute_constants(ir))
660    l_type = ir.module[0].type[0].structure.field[1].read_transform.type
661    self.assertEqual("infinity", l_type.integer.modulus)
662    self.assertEqual("-128", l_type.integer.maximum_value)
663    self.assertEqual("-128", l_type.integer.minimum_value)
664    self.assertEqual("-128", l_type.integer.modular_value)
665
666  def test_upper_bound_of_max(self):
667    ir = self._make_ir("struct Foo:\n"
668                       "  0 [+1]  Int   x\n"
669                       "  1 [+1]  UInt  y\n"
670                       "  let u = $upper_bound($max(x, y))\n")
671    self.assertEqual([], expression_bounds.compute_constants(ir))
672    u_type = ir.module[0].type[0].structure.field[2].read_transform.type
673    self.assertEqual("infinity", u_type.integer.modulus)
674    self.assertEqual("255", u_type.integer.maximum_value)
675    self.assertEqual("255", u_type.integer.minimum_value)
676    self.assertEqual("255", u_type.integer.modular_value)
677
678  def test_lower_bound_of_max(self):
679    ir = self._make_ir("struct Foo:\n"
680                       "  0 [+1]  Int  x\n"
681                       "  1 [+1]  UInt  y\n"
682                       "  let l = $lower_bound($max(x, y))\n")
683    self.assertEqual([], expression_bounds.compute_constants(ir))
684    l_type = ir.module[0].type[0].structure.field[2].read_transform.type
685    self.assertEqual("infinity", l_type.integer.modulus)
686    self.assertEqual("0", l_type.integer.maximum_value)
687    self.assertEqual("0", l_type.integer.minimum_value)
688    self.assertEqual("0", l_type.integer.modular_value)
689
690  def test_double_unbounded_both_ends_times_negative_unbounded(self):
691    ir = self._make_ir(
692        "external Foo:\n"
693        "  [requires: (2 * ($static_size_in_bits - $static_size_in_bits) + 1) "
694        "             * -$static_size_in_bits > 0]\n")
695    self.assertEqual([], expression_bounds.compute_constants(ir))
696    expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
697    self.assertEqual("1", expr.type.integer.modulus)
698    self.assertEqual("0", expr.type.integer.modular_value)
699    self.assertEqual("-infinity", expr.type.integer.minimum_value)
700    self.assertEqual("infinity", expr.type.integer.maximum_value)
701
702  def test_choice_two_non_constant_integers(self):
703    cases = [
704        # t % 12 == 7 and f % 20 == 15 ==> r % 4 == 3
705        (12, 7, 20, 15, 4, 3, -128 * 20 + 15, 127 * 20 + 15),
706        # t % 24 == 15 and f % 12 == 7 ==> r % 4 == 3
707        (24, 15, 12, 7, 4, 3, -128 * 24 + 15, 127 * 24 + 15),
708        # t % 20 == 15 and f % 20 == 10 ==> r % 5 == 0
709        (20, 15, 20, 10, 5, 0, -128 * 20 + 10, 127 * 20 + 15),
710        # t % 20 == 16 and f % 20 == 11 ==> r % 5 == 1
711        (20, 16, 20, 11, 5, 1, -128 * 20 + 11, 127 * 20 + 16),
712    ]
713    for (t_mod, t_val, f_mod, f_val, r_mod, r_val, r_min, r_max) in cases:
714      ir = self._make_ir("struct Foo:\n"
715                         "  0 [+1]    UInt  x\n"
716                         "  1 [+1]    Int   y\n"
717                         "  if (x == 0 ? y * {} + {} : y * {} + {}) == 0:\n"
718                         "    1 [+1]  UInt  z\n".format(
719                             t_mod, t_val, f_mod, f_val))
720      self.assertEqual([], expression_bounds.compute_constants(ir))
721      field = ir.module[0].type[0].structure.field[2]
722      expr = field.existence_condition.function.args[0]
723      self.assertEqual(str(r_mod), expr.type.integer.modulus)
724      self.assertEqual(str(r_val), expr.type.integer.modular_value)
725      self.assertEqual(str(r_min), expr.type.integer.minimum_value)
726      self.assertEqual(str(r_max), expr.type.integer.maximum_value)
727
728  def test_choice_one_non_constant_integer(self):
729    cases = [
730        # t == 35 and f % 20 == 15 ==> res % 20 == 15
731        (35, 20, 15, 20, 15, -128 * 20 + 15, 127 * 20 + 15),
732        # t == 200035 and f % 20 == 15 ==> res % 20 == 15
733        (200035, 20, 15, 20, 15, -128 * 20 + 15, 200035),
734        # t == 21 and f % 20 == 16 ==> res % 5 == 1
735        (21, 20, 16, 5, 1, -128 * 20 + 16, 127 * 20 + 16),
736    ]
737    for (t_val, f_mod, f_val, r_mod, r_val, r_min, r_max) in cases:
738      ir = self._make_ir("struct Foo:\n"
739                         "  0 [+1]    UInt  x\n"
740                         "  1 [+1]    Int   y\n"
741                         "  if (x == 0 ? {0} : y * {1} + {2}) == 0:\n"
742                         "    1 [+1]  UInt  z\n"
743                         "  if (x == 0 ? y * {1} + {2} : {0}) == 0:\n"
744                         "    1 [+1]  UInt  q\n".format(t_val, f_mod, f_val))
745      self.assertEqual([], expression_bounds.compute_constants(ir))
746      field_constant_true = ir.module[0].type[0].structure.field[2]
747      constant_true = field_constant_true.existence_condition.function.args[0]
748      field_constant_false = ir.module[0].type[0].structure.field[3]
749      constant_false = field_constant_false.existence_condition.function.args[0]
750      self.assertEqual(str(r_mod), constant_true.type.integer.modulus)
751      self.assertEqual(str(r_val), constant_true.type.integer.modular_value)
752      self.assertEqual(str(r_min), constant_true.type.integer.minimum_value)
753      self.assertEqual(str(r_max), constant_true.type.integer.maximum_value)
754      self.assertEqual(str(r_mod), constant_false.type.integer.modulus)
755      self.assertEqual(str(r_val), constant_false.type.integer.modular_value)
756      self.assertEqual(str(r_min), constant_false.type.integer.minimum_value)
757      self.assertEqual(str(r_max), constant_false.type.integer.maximum_value)
758
759  def test_choice_two_constant_integers(self):
760    cases = [
761        # t == 10 and f == 7 ==> res % 3 == 1
762        (10, 7, 3, 1, 7, 10),
763        # t == 4 and f == 4 ==> res == 4
764        (4, 4, "infinity", 4, 4, 4),
765    ]
766    for (t_val, f_val, r_mod, r_val, r_min, r_max) in cases:
767      ir = self._make_ir("struct Foo:\n"
768                         "  0 [+1]    UInt  x\n"
769                         "  1 [+1]    Int   y\n"
770                         "  if (x == 0 ? {} : {}) == 0:\n"
771                         "    1 [+1]  UInt  z\n".format(t_val, f_val))
772      self.assertEqual([], expression_bounds.compute_constants(ir))
773      field_constant_true = ir.module[0].type[0].structure.field[2]
774      constant_true = field_constant_true.existence_condition.function.args[0]
775      self.assertEqual(str(r_mod), constant_true.type.integer.modulus)
776      self.assertEqual(str(r_val), constant_true.type.integer.modular_value)
777      self.assertEqual(str(r_min), constant_true.type.integer.minimum_value)
778      self.assertEqual(str(r_max), constant_true.type.integer.maximum_value)
779
780  def test_constant_true_has(self):
781    ir = self._make_ir("struct Foo:\n"
782                       "  if $present(x):\n"
783                       "    1 [+1]  UInt  q\n"
784                       "  0 [+1]    UInt  x\n"
785                       "  if x > 10:\n"
786                       "    1 [+1]  Int   y\n"
787                       "  if false:\n"
788                       "    2 [+1]  Int   z\n")
789    self.assertEqual([], expression_bounds.compute_constants(ir))
790    field = ir.module[0].type[0].structure.field[0]
791    has_func = field.existence_condition
792    self.assertTrue(has_func.type.boolean.value)
793
794  def test_constant_false_has(self):
795    ir = self._make_ir("struct Foo:\n"
796                       "  if $present(z):\n"
797                       "    1 [+1]  UInt  q\n"
798                       "  0 [+1]    UInt  x\n"
799                       "  if x > 10:\n"
800                       "    1 [+1]  Int   y\n"
801                       "  if false:\n"
802                       "    2 [+1]  Int   z\n")
803    self.assertEqual([], expression_bounds.compute_constants(ir))
804    field = ir.module[0].type[0].structure.field[0]
805    has_func = field.existence_condition
806    self.assertTrue(has_func.type.boolean.HasField("value"))
807    self.assertFalse(has_func.type.boolean.value)
808
809  def test_variable_has(self):
810    ir = self._make_ir("struct Foo:\n"
811                       "  if $present(y):\n"
812                       "    1 [+1]  UInt  q\n"
813                       "  0 [+1]    UInt  x\n"
814                       "  if x > 10:\n"
815                       "    1 [+1]  Int   y\n"
816                       "  if false:\n"
817                       "    2 [+1]  Int   z\n")
818    self.assertEqual([], expression_bounds.compute_constants(ir))
819    field = ir.module[0].type[0].structure.field[0]
820    has_func = field.existence_condition
821    self.assertFalse(has_func.type.boolean.HasField("value"))
822
823  def test_max_of_constants(self):
824    ir = self._make_ir("struct Foo:\n"
825                       "  0 [+1]    UInt  x\n"
826                       "  1 [+1]    Int   y\n"
827                       "  if $max(0, 1, 2) == 0:\n"
828                       "    1 [+1]  UInt  z\n")
829    self.assertEqual([], expression_bounds.compute_constants(ir))
830    field = ir.module[0].type[0].structure.field[2]
831    max_func = field.existence_condition.function.args[0]
832    self.assertEqual("infinity", max_func.type.integer.modulus)
833    self.assertEqual("2", max_func.type.integer.modular_value)
834    self.assertEqual("2", max_func.type.integer.minimum_value)
835    self.assertEqual("2", max_func.type.integer.maximum_value)
836
837  def test_max_dominated_by_constant(self):
838    ir = self._make_ir("struct Foo:\n"
839                       "  0 [+1]    UInt  x\n"
840                       "  1 [+1]    Int   y\n"
841                       "  if $max(x, y, 255) == 0:\n"
842                       "    1 [+1]  UInt  z\n")
843    self.assertEqual([], expression_bounds.compute_constants(ir))
844    field = ir.module[0].type[0].structure.field[2]
845    max_func = field.existence_condition.function.args[0]
846    self.assertEqual("infinity", max_func.type.integer.modulus)
847    self.assertEqual("255", max_func.type.integer.modular_value)
848    self.assertEqual("255", max_func.type.integer.minimum_value)
849    self.assertEqual("255", max_func.type.integer.maximum_value)
850
851  def test_max_of_variables(self):
852    ir = self._make_ir("struct Foo:\n"
853                       "  0 [+1]    UInt  x\n"
854                       "  1 [+1]    Int   y\n"
855                       "  if $max(x, y) == 0:\n"
856                       "    1 [+1]  UInt  z\n")
857    self.assertEqual([], expression_bounds.compute_constants(ir))
858    field = ir.module[0].type[0].structure.field[2]
859    max_func = field.existence_condition.function.args[0]
860    self.assertEqual("1", max_func.type.integer.modulus)
861    self.assertEqual("0", max_func.type.integer.modular_value)
862    self.assertEqual("0", max_func.type.integer.minimum_value)
863    self.assertEqual("255", max_func.type.integer.maximum_value)
864
865  def test_max_of_variables_with_shared_modulus(self):
866    ir = self._make_ir("struct Foo:\n"
867                       "  0 [+1]    UInt  x\n"
868                       "  1 [+1]    Int   y\n"
869                       "  if $max(x * 8 + 5, y * 4 + 3) == 0:\n"
870                       "    1 [+1]  UInt  z\n")
871    self.assertEqual([], expression_bounds.compute_constants(ir))
872    field = ir.module[0].type[0].structure.field[2]
873    max_func = field.existence_condition.function.args[0]
874    self.assertEqual("2", max_func.type.integer.modulus)
875    self.assertEqual("1", max_func.type.integer.modular_value)
876    self.assertEqual("5", max_func.type.integer.minimum_value)
877    self.assertEqual("2045", max_func.type.integer.maximum_value)
878
879  def test_max_of_three_variables(self):
880    ir = self._make_ir("struct Foo:\n"
881                       "  0 [+1]    UInt  x\n"
882                       "  1 [+1]    Int   y\n"
883                       "  2 [+2]    Int   z\n"
884                       "  if $max(x, y, z) == 0:\n"
885                       "    1 [+1]  UInt  q\n")
886    self.assertEqual([], expression_bounds.compute_constants(ir))
887    field = ir.module[0].type[0].structure.field[3]
888    max_func = field.existence_condition.function.args[0]
889    self.assertEqual("1", max_func.type.integer.modulus)
890    self.assertEqual("0", max_func.type.integer.modular_value)
891    self.assertEqual("0", max_func.type.integer.minimum_value)
892    self.assertEqual("32767", max_func.type.integer.maximum_value)
893
894  def test_max_of_one_variable(self):
895    ir = self._make_ir("struct Foo:\n"
896                       "  0 [+1]    UInt  x\n"
897                       "  1 [+1]    Int   y\n"
898                       "  2 [+2]    Int   z\n"
899                       "  if $max(x * 2 + 3) == 0:\n"
900                       "    1 [+1]  UInt  q\n")
901    self.assertEqual([], expression_bounds.compute_constants(ir))
902    field = ir.module[0].type[0].structure.field[3]
903    max_func = field.existence_condition.function.args[0]
904    self.assertEqual("2", max_func.type.integer.modulus)
905    self.assertEqual("1", max_func.type.integer.modular_value)
906    self.assertEqual("3", max_func.type.integer.minimum_value)
907    self.assertEqual("513", max_func.type.integer.maximum_value)
908
909  def test_max_of_one_variable_and_one_constant(self):
910    ir = self._make_ir("struct Foo:\n"
911                       "  0 [+1]    UInt  x\n"
912                       "  1 [+1]    Int   y\n"
913                       "  2 [+2]    Int   z\n"
914                       "  if $max(x * 2 + 3, 311) == 0:\n"
915                       "    1 [+1]  UInt  q\n")
916    self.assertEqual([], expression_bounds.compute_constants(ir))
917    field = ir.module[0].type[0].structure.field[3]
918    max_func = field.existence_condition.function.args[0]
919    self.assertEqual("2", max_func.type.integer.modulus)
920    self.assertEqual("1", max_func.type.integer.modular_value)
921    self.assertEqual("311", max_func.type.integer.minimum_value)
922    self.assertEqual("513", max_func.type.integer.maximum_value)
923
924  def test_choice_non_integer_arguments(self):
925    ir = self._make_ir("struct Foo:\n"
926                       "  0 [+1]    UInt  x\n"
927                       "  if x == 0 ? false : true:\n"
928                       "    1 [+1]  UInt  y\n")
929    self.assertEqual([], expression_bounds.compute_constants(ir))
930    expr = ir.module[0].type[0].structure.field[1].existence_condition
931    self.assertEqual("boolean", expr.type.WhichOneof("type"))
932    self.assertFalse(expr.type.boolean.HasField("value"))
933
934  def test_uint_value_range_for_explicit_size(self):
935    ir = self._make_ir("struct Foo:\n"
936                       "  0 [+1]  UInt     x\n"
937                       "  1 [+x]  UInt:16  y\n"
938                       "  y [+1]  UInt     z\n")
939    self.assertEqual([], expression_bounds.compute_constants(ir))
940    z_start = ir.module[0].type[0].structure.field[2].location.start
941    self.assertEqual("1", z_start.type.integer.modulus)
942    self.assertEqual("0", z_start.type.integer.modular_value)
943    self.assertEqual("0", z_start.type.integer.minimum_value)
944    self.assertEqual("65535", z_start.type.integer.maximum_value)
945
946  def test_uint_value_ranges(self):
947    cases = [
948        (1, 1),
949        (2, 3),
950        (3, 7),
951        (4, 15),
952        (8, 255),
953        (12, 4095),
954        (15, 32767),
955        (16, 65535),
956        (32, 4294967295),
957        (48, 281474976710655),
958        (64, 18446744073709551615),
959    ]
960    for bits, upper in cases:
961      ir = self._make_ir("struct Foo:\n"
962                         "  0   [+8]   bits:\n"
963                         "    0 [+{}]  UInt  x\n"
964                         "  x   [+1]   UInt  z\n".format(bits))
965      self.assertEqual([], expression_bounds.compute_constants(ir))
966      z_start = ir.module[0].type[0].structure.field[2].location.start
967      self.assertEqual("1", z_start.type.integer.modulus)
968      self.assertEqual("0", z_start.type.integer.modular_value)
969      self.assertEqual("0", z_start.type.integer.minimum_value)
970      self.assertEqual(str(upper), z_start.type.integer.maximum_value)
971
972  def test_int_value_ranges(self):
973    cases = [
974        (1, -1, 0),
975        (2, -2, 1),
976        (3, -4, 3),
977        (4, -8, 7),
978        (8, -128, 127),
979        (12, -2048, 2047),
980        (15, -16384, 16383),
981        (16, -32768, 32767),
982        (32, -2147483648, 2147483647),
983        (48, -140737488355328, 140737488355327),
984        (64, -9223372036854775808, 9223372036854775807),
985    ]
986    for bits, lower, upper in cases:
987      ir = self._make_ir("struct Foo:\n"
988                         "  0   [+8]   bits:\n"
989                         "    0 [+{}]  Int   x\n"
990                         "  x   [+1]   UInt  z\n".format(bits))
991      self.assertEqual([], expression_bounds.compute_constants(ir))
992      z_start = ir.module[0].type[0].structure.field[2].location.start
993      self.assertEqual("1", z_start.type.integer.modulus)
994      self.assertEqual("0", z_start.type.integer.modular_value)
995      self.assertEqual(str(lower), z_start.type.integer.minimum_value)
996      self.assertEqual(str(upper), z_start.type.integer.maximum_value)
997
998  def test_bcd_value_ranges(self):
999    cases = [
1000        (1, 1),
1001        (2, 3),
1002        (3, 7),
1003        (4, 9),
1004        (8, 99),
1005        (12, 999),
1006        (15, 7999),
1007        (16, 9999),
1008        (32, 99999999),
1009        (48, 999999999999),
1010        (64, 9999999999999999),
1011    ]
1012    for bits, upper in cases:
1013      ir = self._make_ir("struct Foo:\n"
1014                         "  0   [+8]   bits:\n"
1015                         "    0 [+{}]  Bcd   x\n"
1016                         "  x   [+1]   UInt  z\n".format(bits))
1017      self.assertEqual([], expression_bounds.compute_constants(ir))
1018      z_start = ir.module[0].type[0].structure.field[2].location.start
1019      self.assertEqual("1", z_start.type.integer.modulus)
1020      self.assertEqual("0", z_start.type.integer.modular_value)
1021      self.assertEqual("0", z_start.type.integer.minimum_value)
1022      self.assertEqual(str(upper), z_start.type.integer.maximum_value)
1023
1024  def test_virtual_field_bounds(self):
1025    ir = self._make_ir("struct Foo:\n"
1026                       "  0 [+1]  UInt     x\n"
1027                       "  let y = x + 10\n")
1028    self.assertEqual([], expression_bounds.compute_constants(ir))
1029    field_y = ir.module[0].type[0].structure.field[1]
1030    self.assertEqual("1", field_y.read_transform.type.integer.modulus)
1031    self.assertEqual("0", field_y.read_transform.type.integer.modular_value)
1032    self.assertEqual("10", field_y.read_transform.type.integer.minimum_value)
1033    self.assertEqual("265", field_y.read_transform.type.integer.maximum_value)
1034
1035  def test_virtual_field_bounds_copied(self):
1036    ir = self._make_ir("struct Foo:\n"
1037                       "  let z = y + 100\n"
1038                       "  let y = x + 10\n"
1039                       "  0 [+1]  UInt     x\n")
1040    self.assertEqual([], expression_bounds.compute_constants(ir))
1041    field_z = ir.module[0].type[0].structure.field[0]
1042    self.assertEqual("1", field_z.read_transform.type.integer.modulus)
1043    self.assertEqual("0", field_z.read_transform.type.integer.modular_value)
1044    self.assertEqual("110", field_z.read_transform.type.integer.minimum_value)
1045    self.assertEqual("365", field_z.read_transform.type.integer.maximum_value)
1046    y_reference = field_z.read_transform.function.args[0]
1047    self.assertEqual("1", y_reference.type.integer.modulus)
1048    self.assertEqual("0", y_reference.type.integer.modular_value)
1049    self.assertEqual("10", y_reference.type.integer.minimum_value)
1050    self.assertEqual("265", y_reference.type.integer.maximum_value)
1051
1052  def test_constant_reference_to_virtual_bounds_copied(self):
1053    ir = self._make_ir("struct Foo:\n"
1054                       "  let ten = Bar.ten\n"
1055                       "  let truth = Bar.truth\n"
1056                       "struct Bar:\n"
1057                       "  let ten = 10\n"
1058                       "  let truth = true\n")
1059    self.assertEqual([], expression_bounds.compute_constants(ir))
1060    field_ten = ir.module[0].type[0].structure.field[0]
1061    self.assertEqual("infinity", field_ten.read_transform.type.integer.modulus)
1062    self.assertEqual("10", field_ten.read_transform.type.integer.modular_value)
1063    self.assertEqual("10", field_ten.read_transform.type.integer.minimum_value)
1064    self.assertEqual("10", field_ten.read_transform.type.integer.maximum_value)
1065    field_truth = ir.module[0].type[0].structure.field[1]
1066    self.assertTrue(field_truth.read_transform.type.boolean.value)
1067
1068  def test_forward_reference_to_reference_to_enum_correctly_calculated(self):
1069    ir = self._make_ir("struct Foo:\n"
1070                       "  let ten = Bar.TEN\n"
1071                       "enum Bar:\n"
1072                       "  TEN = TEN2\n"
1073                       "  TEN2 = 5 + 5\n")
1074    self.assertEqual([], expression_bounds.compute_constants(ir))
1075    field_ten = ir.module[0].type[0].structure.field[0]
1076    self.assertEqual("10", field_ten.read_transform.type.enumeration.value)
1077
1078
1079class InfinityAugmentedArithmeticTest(unittest.TestCase):
1080
1081  # TODO(bolms): Will there ever be any situations where all elements of the arg
1082  # to _min would be "infinity"?
1083  def test_min_of_infinities(self):
1084    self.assertEqual("infinity",
1085                     expression_bounds._min(["infinity", "infinity"]))
1086
1087  # TODO(bolms): Will there ever be any situations where all elements of the arg
1088  # to _max would be "-infinity"?
1089  def test_max_of_negative_infinities(self):
1090    self.assertEqual("-infinity",
1091                     expression_bounds._max(["-infinity", "-infinity"]))
1092
1093  def test_shared_modular_value_of_identical_modulus_and_value(self):
1094    self.assertEqual((10, 8),
1095                     expression_bounds._shared_modular_value((10, 8), (10, 8)))
1096
1097  def test_shared_modular_value_of_identical_modulus(self):
1098    self.assertEqual((5, 3),
1099                     expression_bounds._shared_modular_value((10, 8), (10, 3)))
1100
1101  def test_shared_modular_value_of_identical_value(self):
1102    self.assertEqual((6, 2),
1103                     expression_bounds._shared_modular_value((18, 2), (12, 2)))
1104
1105  def test_shared_modular_value_of_different_arguments(self):
1106    self.assertEqual((7, 4),
1107                     expression_bounds._shared_modular_value((21, 11), (14, 4)))
1108
1109  def test_shared_modular_value_of_infinity_and_non(self):
1110    self.assertEqual((7, 4),
1111                     expression_bounds._shared_modular_value(("infinity", 25),
1112                                                             (14, 4)))
1113
1114  def test_shared_modular_value_of_infinity_and_infinity(self):
1115    self.assertEqual((14, 5),
1116                     expression_bounds._shared_modular_value(("infinity", 19),
1117                                                             ("infinity", 5)))
1118
1119  def test_shared_modular_value_of_infinity_and_identical_value(self):
1120    self.assertEqual(("infinity", 5),
1121                     expression_bounds._shared_modular_value(("infinity", 5),
1122                                                             ("infinity", 5)))
1123
1124
1125if __name__ == "__main__":
1126  unittest.main()
1127