blob: 15870b465af6d128846a49cf85151ce69afced73 [file] [log] [blame]
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for expression_bounds."""
import unittest
from compiler.front_end import expression_bounds
from compiler.front_end import glue
from compiler.front_end import test_util
class ComputeConstantsTest(unittest.TestCase):
def _make_ir(self, emb_text):
ir, unused_debug_info, errors = glue.parse_emboss_file(
"m.emb",
test_util.dict_file_reader({"m.emb": emb_text}),
stop_before_step="compute_constants")
assert not errors, errors
return ir
def test_constant_integer(self):
ir = self._make_ir("struct Foo:\n"
" 10 [+1] UInt x\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
start = ir.module[0].type[0].structure.field[0].location.start
self.assertEqual("10", start.type.integer.minimum_value)
self.assertEqual("10", start.type.integer.maximum_value)
self.assertEqual("10", start.type.integer.modular_value)
self.assertEqual("infinity", start.type.integer.modulus)
def test_boolean_constant(self):
ir = self._make_ir("struct Foo:\n"
" if true:\n"
" 0 [+1] UInt x\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expression = ir.module[0].type[0].structure.field[0].existence_condition
self.assertTrue(expression.type.boolean.HasField("value"))
self.assertTrue(expression.type.boolean.value)
def test_constant_equality(self):
ir = self._make_ir("struct Foo:\n"
" if 5 == 5:\n"
" 0 [+1] UInt x\n"
" if 5 == 6:\n"
" 0 [+1] UInt y\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
structure = ir.module[0].type[0].structure
true_condition = structure.field[0].existence_condition
false_condition = structure.field[1].existence_condition
self.assertTrue(true_condition.type.boolean.HasField("value"))
self.assertTrue(true_condition.type.boolean.value)
self.assertTrue(false_condition.type.boolean.HasField("value"))
self.assertFalse(false_condition.type.boolean.value)
def test_constant_inequality(self):
ir = self._make_ir("struct Foo:\n"
" if 5 != 5:\n"
" 0 [+1] UInt x\n"
" if 5 != 6:\n"
" 0 [+1] UInt y\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
structure = ir.module[0].type[0].structure
false_condition = structure.field[0].existence_condition
true_condition = structure.field[1].existence_condition
self.assertTrue(false_condition.type.boolean.HasField("value"))
self.assertFalse(false_condition.type.boolean.value)
self.assertTrue(true_condition.type.boolean.HasField("value"))
self.assertTrue(true_condition.type.boolean.value)
def test_constant_less_than(self):
ir = self._make_ir("struct Foo:\n"
" if 5 < 4:\n"
" 0 [+1] UInt x\n"
" if 5 < 5:\n"
" 0 [+1] UInt y\n"
" if 5 < 6:\n"
" 0 [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
structure = ir.module[0].type[0].structure
greater_than_condition = structure.field[0].existence_condition
equal_condition = structure.field[1].existence_condition
less_than_condition = structure.field[2].existence_condition
self.assertTrue(greater_than_condition.type.boolean.HasField("value"))
self.assertFalse(greater_than_condition.type.boolean.value)
self.assertTrue(equal_condition.type.boolean.HasField("value"))
self.assertFalse(equal_condition.type.boolean.value)
self.assertTrue(less_than_condition.type.boolean.HasField("value"))
self.assertTrue(less_than_condition.type.boolean.value)
def test_constant_less_than_or_equal(self):
ir = self._make_ir("struct Foo:\n"
" if 5 <= 4:\n"
" 0 [+1] UInt x\n"
" if 5 <= 5:\n"
" 0 [+1] UInt y\n"
" if 5 <= 6:\n"
" 0 [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
structure = ir.module[0].type[0].structure
greater_than_condition = structure.field[0].existence_condition
equal_condition = structure.field[1].existence_condition
less_than_condition = structure.field[2].existence_condition
self.assertTrue(greater_than_condition.type.boolean.HasField("value"))
self.assertFalse(greater_than_condition.type.boolean.value)
self.assertTrue(equal_condition.type.boolean.HasField("value"))
self.assertTrue(equal_condition.type.boolean.value)
self.assertTrue(less_than_condition.type.boolean.HasField("value"))
self.assertTrue(less_than_condition.type.boolean.value)
def test_constant_greater_than(self):
ir = self._make_ir("struct Foo:\n"
" if 5 > 4:\n"
" 0 [+1] UInt x\n"
" if 5 > 5:\n"
" 0 [+1] UInt y\n"
" if 5 > 6:\n"
" 0 [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
structure = ir.module[0].type[0].structure
greater_than_condition = structure.field[0].existence_condition
equal_condition = structure.field[1].existence_condition
less_than_condition = structure.field[2].existence_condition
self.assertTrue(greater_than_condition.type.boolean.HasField("value"))
self.assertTrue(greater_than_condition.type.boolean.value)
self.assertTrue(equal_condition.type.boolean.HasField("value"))
self.assertFalse(equal_condition.type.boolean.value)
self.assertTrue(less_than_condition.type.boolean.HasField("value"))
self.assertFalse(less_than_condition.type.boolean.value)
def test_constant_greater_than_or_equal(self):
ir = self._make_ir("struct Foo:\n"
" if 5 >= 4:\n"
" 0 [+1] UInt x\n"
" if 5 >= 5:\n"
" 0 [+1] UInt y\n"
" if 5 >= 6:\n"
" 0 [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
structure = ir.module[0].type[0].structure
greater_than_condition = structure.field[0].existence_condition
equal_condition = structure.field[1].existence_condition
less_than_condition = structure.field[2].existence_condition
self.assertTrue(greater_than_condition.type.boolean.HasField("value"))
self.assertTrue(greater_than_condition.type.boolean.value)
self.assertTrue(equal_condition.type.boolean.HasField("value"))
self.assertTrue(equal_condition.type.boolean.value)
self.assertTrue(less_than_condition.type.boolean.HasField("value"))
self.assertFalse(less_than_condition.type.boolean.value)
def test_constant_and(self):
ir = self._make_ir("struct Foo:\n"
" if false && false:\n"
" 0 [+1] UInt x\n"
" if true && false:\n"
" 0 [+1] UInt y\n"
" if false && true:\n"
" 0 [+1] UInt z\n"
" if true && true:\n"
" 0 [+1] UInt w\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
structure = ir.module[0].type[0].structure
false_false_condition = structure.field[0].existence_condition
true_false_condition = structure.field[1].existence_condition
false_true_condition = structure.field[2].existence_condition
true_true_condition = structure.field[3].existence_condition
self.assertTrue(false_false_condition.type.boolean.HasField("value"))
self.assertFalse(false_false_condition.type.boolean.value)
self.assertTrue(true_false_condition.type.boolean.HasField("value"))
self.assertFalse(true_false_condition.type.boolean.value)
self.assertTrue(false_true_condition.type.boolean.HasField("value"))
self.assertFalse(false_true_condition.type.boolean.value)
self.assertTrue(true_true_condition.type.boolean.HasField("value"))
self.assertTrue(true_true_condition.type.boolean.value)
def test_constant_or(self):
ir = self._make_ir("struct Foo:\n"
" if false || false:\n"
" 0 [+1] UInt x\n"
" if true || false:\n"
" 0 [+1] UInt y\n"
" if false || true:\n"
" 0 [+1] UInt z\n"
" if true || true:\n"
" 0 [+1] UInt w\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
structure = ir.module[0].type[0].structure
false_false_condition = structure.field[0].existence_condition
true_false_condition = structure.field[1].existence_condition
false_true_condition = structure.field[2].existence_condition
true_true_condition = structure.field[3].existence_condition
self.assertTrue(false_false_condition.type.boolean.HasField("value"))
self.assertFalse(false_false_condition.type.boolean.value)
self.assertTrue(true_false_condition.type.boolean.HasField("value"))
self.assertTrue(true_false_condition.type.boolean.value)
self.assertTrue(false_true_condition.type.boolean.HasField("value"))
self.assertTrue(false_true_condition.type.boolean.value)
self.assertTrue(true_true_condition.type.boolean.HasField("value"))
self.assertTrue(true_true_condition.type.boolean.value)
def test_enum_constant(self):
ir = self._make_ir("struct Foo:\n"
" if Bar.QUX == Bar.QUX:\n"
" 0 [+1] Bar x\n"
"enum Bar:\n"
" QUX = 12\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
condition = ir.module[0].type[0].structure.field[0].existence_condition
left = condition.function.args[0]
self.assertEqual("12", left.type.enumeration.value)
def test_non_constant_field_reference(self):
ir = self._make_ir("struct Foo:\n"
" y [+1] UInt x\n"
" 0 [+1] UInt y\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
start = ir.module[0].type[0].structure.field[0].location.start
self.assertEqual("0", start.type.integer.minimum_value)
self.assertEqual("255", start.type.integer.maximum_value)
self.assertEqual("0", start.type.integer.modular_value)
self.assertEqual("1", start.type.integer.modulus)
def test_field_reference_bounds_are_uncomputable(self):
# Variable-sized UInt/Int/Bcd should not cause an error here: they are
# handled in the constraints pass.
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 0 [+x] UInt y\n"
" y [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
def test_field_references_references_bounds_are_uncomputable(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 0 [+x] UInt y\n"
" 0 [+y] UInt z\n"
" z [+1] UInt q\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
def test_non_constant_equality(self):
ir = self._make_ir("struct Foo:\n"
" if 5 == y:\n"
" 0 [+1] UInt x\n"
" 0 [+1] UInt y\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
structure = ir.module[0].type[0].structure
condition = structure.field[0].existence_condition
self.assertFalse(condition.type.boolean.HasField("value"))
def test_constant_addition(self):
ir = self._make_ir("struct Foo:\n"
" 7+5 [+1] UInt x\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
start = ir.module[0].type[0].structure.field[0].location.start
self.assertEqual("12", start.type.integer.minimum_value)
self.assertEqual("12", start.type.integer.maximum_value)
self.assertEqual("12", start.type.integer.modular_value)
self.assertEqual("infinity", start.type.integer.modulus)
self.assertEqual("7", start.function.args[0].type.integer.minimum_value)
self.assertEqual("7", start.function.args[0].type.integer.maximum_value)
self.assertEqual("7", start.function.args[0].type.integer.modular_value)
self.assertEqual("infinity", start.type.integer.modulus)
self.assertEqual("5", start.function.args[1].type.integer.minimum_value)
self.assertEqual("5", start.function.args[1].type.integer.maximum_value)
self.assertEqual("5", start.function.args[1].type.integer.modular_value)
self.assertEqual("infinity", start.type.integer.modulus)
def test_constant_subtraction(self):
ir = self._make_ir("struct Foo:\n"
" 7-5 [+1] UInt x\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
start = ir.module[0].type[0].structure.field[0].location.start
self.assertEqual("2", start.type.integer.minimum_value)
self.assertEqual("2", start.type.integer.maximum_value)
self.assertEqual("2", start.type.integer.modular_value)
self.assertEqual("infinity", start.type.integer.modulus)
self.assertEqual("7", start.function.args[0].type.integer.minimum_value)
self.assertEqual("7", start.function.args[0].type.integer.maximum_value)
self.assertEqual("7", start.function.args[0].type.integer.modular_value)
self.assertEqual("infinity", start.type.integer.modulus)
self.assertEqual("5", start.function.args[1].type.integer.minimum_value)
self.assertEqual("5", start.function.args[1].type.integer.maximum_value)
self.assertEqual("5", start.function.args[1].type.integer.modular_value)
self.assertEqual("infinity", start.type.integer.modulus)
def test_constant_multiplication(self):
ir = self._make_ir("struct Foo:\n"
" 7*5 [+1] UInt x\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
start = ir.module[0].type[0].structure.field[0].location.start
self.assertEqual("35", start.type.integer.minimum_value)
self.assertEqual("35", start.type.integer.maximum_value)
self.assertEqual("35", start.type.integer.modular_value)
self.assertEqual("infinity", start.type.integer.modulus)
self.assertEqual("7", start.function.args[0].type.integer.minimum_value)
self.assertEqual("7", start.function.args[0].type.integer.maximum_value)
self.assertEqual("7", start.function.args[0].type.integer.modular_value)
self.assertEqual("infinity", start.type.integer.modulus)
self.assertEqual("5", start.function.args[1].type.integer.minimum_value)
self.assertEqual("5", start.function.args[1].type.integer.maximum_value)
self.assertEqual("5", start.function.args[1].type.integer.modular_value)
self.assertEqual("infinity", start.type.integer.modulus)
def test_nested_constant_expression(self):
ir = self._make_ir("struct Foo:\n"
" if 7*(3+1) == 28:\n"
" 0 [+1] UInt x\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
condition = ir.module[0].type[0].structure.field[0].existence_condition
self.assertTrue(condition.type.boolean.value)
condition_left = condition.function.args[0]
self.assertEqual("28", condition_left.type.integer.minimum_value)
self.assertEqual("28", condition_left.type.integer.maximum_value)
self.assertEqual("28", condition_left.type.integer.modular_value)
self.assertEqual("infinity", condition_left.type.integer.modulus)
condition_left_left = condition_left.function.args[0]
self.assertEqual("7", condition_left_left.type.integer.minimum_value)
self.assertEqual("7", condition_left_left.type.integer.maximum_value)
self.assertEqual("7", condition_left_left.type.integer.modular_value)
self.assertEqual("infinity", condition_left_left.type.integer.modulus)
condition_left_right = condition_left.function.args[1]
self.assertEqual("4", condition_left_right.type.integer.minimum_value)
self.assertEqual("4", condition_left_right.type.integer.maximum_value)
self.assertEqual("4", condition_left_right.type.integer.modular_value)
self.assertEqual("infinity", condition_left_right.type.integer.modulus)
condition_left_right_left = condition_left_right.function.args[0]
self.assertEqual("3", condition_left_right_left.type.integer.minimum_value)
self.assertEqual("3", condition_left_right_left.type.integer.maximum_value)
self.assertEqual("3", condition_left_right_left.type.integer.modular_value)
self.assertEqual("infinity", condition_left_right_left.type.integer.modulus)
condition_left_right_right = condition_left_right.function.args[1]
self.assertEqual("1", condition_left_right_right.type.integer.minimum_value)
self.assertEqual("1", condition_left_right_right.type.integer.maximum_value)
self.assertEqual("1", condition_left_right_right.type.integer.modular_value)
self.assertEqual("infinity",
condition_left_right_right.type.integer.modulus)
def test_constant_plus_non_constant(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 5+(4*x) [+1] UInt y\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
y_start = ir.module[0].type[0].structure.field[1].location.start
self.assertEqual("4", y_start.type.integer.modulus)
self.assertEqual("1", y_start.type.integer.modular_value)
self.assertEqual("5", y_start.type.integer.minimum_value)
self.assertEqual("1025", y_start.type.integer.maximum_value)
def test_constant_minus_non_constant(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 5-(4*x) [+1] UInt y\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
y_start = ir.module[0].type[0].structure.field[1].location.start
self.assertEqual("4", y_start.type.integer.modulus)
self.assertEqual("1", y_start.type.integer.modular_value)
self.assertEqual("-1015", y_start.type.integer.minimum_value)
self.assertEqual("5", y_start.type.integer.maximum_value)
def test_non_constant_minus_constant(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" (4*x)-5 [+1] UInt y\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
y_start = ir.module[0].type[0].structure.field[1].location.start
self.assertEqual(str((4 * 0) - 5), y_start.type.integer.minimum_value)
self.assertEqual(str((4 * 255) - 5), y_start.type.integer.maximum_value)
self.assertEqual("4", y_start.type.integer.modulus)
self.assertEqual("3", y_start.type.integer.modular_value)
def test_non_constant_plus_non_constant(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] UInt y\n"
" (4*x)+(6*y+3) [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("3", z_start.type.integer.minimum_value)
self.assertEqual(str(4 * 255 + 6 * 255 + 3),
z_start.type.integer.maximum_value)
self.assertEqual("2", z_start.type.integer.modulus)
self.assertEqual("1", z_start.type.integer.modular_value)
def test_non_constant_minus_non_constant(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] UInt y\n"
" (x*3)-(y*3) [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("3", z_start.type.integer.modulus)
self.assertEqual("0", z_start.type.integer.modular_value)
self.assertEqual(str(-3 * 255), z_start.type.integer.minimum_value)
self.assertEqual(str(3 * 255), z_start.type.integer.maximum_value)
def test_non_constant_times_constant(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" (4*x+1)*5 [+1] UInt y\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
y_start = ir.module[0].type[0].structure.field[1].location.start
self.assertEqual("20", y_start.type.integer.modulus)
self.assertEqual("5", y_start.type.integer.modular_value)
self.assertEqual("5", y_start.type.integer.minimum_value)
self.assertEqual(str((4 * 255 + 1) * 5), y_start.type.integer.maximum_value)
def test_non_constant_times_negative_constant(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" (4*x+1)*-5 [+1] UInt y\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
y_start = ir.module[0].type[0].structure.field[1].location.start
self.assertEqual("20", y_start.type.integer.modulus)
self.assertEqual("15", y_start.type.integer.modular_value)
self.assertEqual(str((4 * 255 + 1) * -5),
y_start.type.integer.minimum_value)
self.assertEqual("-5", y_start.type.integer.maximum_value)
def test_non_constant_times_zero(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" (4*x+1)*0 [+1] UInt y\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
y_start = ir.module[0].type[0].structure.field[1].location.start
self.assertEqual("infinity", y_start.type.integer.modulus)
self.assertEqual("0", y_start.type.integer.modular_value)
self.assertEqual("0", y_start.type.integer.minimum_value)
self.assertEqual("0", y_start.type.integer.maximum_value)
def test_non_constant_times_non_constant_shared_modulus(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] UInt y\n"
" (4*x+3)*(4*y+3) [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("4", z_start.type.integer.modulus)
self.assertEqual("1", z_start.type.integer.modular_value)
self.assertEqual("9", z_start.type.integer.minimum_value)
self.assertEqual(str((4 * 255 + 3)**2), z_start.type.integer.maximum_value)
def test_non_constant_times_non_constant_congruent_to_zero(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] UInt y\n"
" (4*x)*(4*y) [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("16", z_start.type.integer.modulus)
self.assertEqual("0", z_start.type.integer.modular_value)
self.assertEqual("0", z_start.type.integer.minimum_value)
self.assertEqual(str((4 * 255)**2), z_start.type.integer.maximum_value)
def test_non_constant_times_non_constant_partially_shared_modulus(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] UInt y\n"
" (4*x+3)*(8*y+3) [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("4", z_start.type.integer.modulus)
self.assertEqual("1", z_start.type.integer.modular_value)
self.assertEqual("9", z_start.type.integer.minimum_value)
self.assertEqual(str((4 * 255 + 3) * (8 * 255 + 3)),
z_start.type.integer.maximum_value)
def test_non_constant_times_non_constant_full_complexity(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] UInt y\n"
" (12*x+9)*(40*y+15) [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("60", z_start.type.integer.modulus)
self.assertEqual("15", z_start.type.integer.modular_value)
self.assertEqual(str(9 * 15), z_start.type.integer.minimum_value)
self.assertEqual(str((12 * 255 + 9) * (40 * 255 + 15)),
z_start.type.integer.maximum_value)
def test_signed_non_constant_times_signed_non_constant_full_complexity(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] Int x\n"
" 1 [+1] Int y\n"
" (12*x+9)*(40*y+15) [+1] Int z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("60", z_start.type.integer.modulus)
self.assertEqual("15", z_start.type.integer.modular_value)
# Max x/min y is slightly lower than min x/max y (-7825965 vs -7780065).
self.assertEqual(str((12 * 127 + 9) * (40 * -128 + 15)),
z_start.type.integer.minimum_value)
# Max x/max y is slightly higher than min x/min y (7810635 vs 7795335).
self.assertEqual(str((12 * 127 + 9) * (40 * 127 + 15)),
z_start.type.integer.maximum_value)
def test_non_constant_times_non_constant_flipped_min_max(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] UInt y\n"
" (-x*3)*(y*3) [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("9", z_start.type.integer.modulus)
self.assertEqual("0", z_start.type.integer.modular_value)
self.assertEqual(str(-((3 * 255)**2)), z_start.type.integer.minimum_value)
self.assertEqual("0", z_start.type.integer.maximum_value)
# Currently, only `$static_size_in_bits` has an infinite bound, so all of the
# examples below use `$static_size_in_bits`. Unfortunately, this also means
# that these tests rely on the fact that Emboss doesn't try to do any term
# rewriting or smart correlation between the arguments of various operators:
# for example, several tests rely on `$static_size_in_bits -
# $static_size_in_bits` having the range `-infinity` to `infinity`, when a
# trivial term rewrite would turn that expression into `0`.
#
# Unbounded expressions are only allowed at compile-time anyway, so these
# tests cover some fairly unlikely uses of the Emboss expression language.
def test_unbounded_plus_constant(self):
ir = self._make_ir("external Foo:\n"
" [requires: $static_size_in_bits + 2 > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("1", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("2", expr.type.integer.minimum_value)
self.assertEqual("infinity", expr.type.integer.maximum_value)
def test_negative_unbounded_plus_constant(self):
ir = self._make_ir("external Foo:\n"
" [requires: -$static_size_in_bits + 2 > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("1", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("-infinity", expr.type.integer.minimum_value)
self.assertEqual("2", expr.type.integer.maximum_value)
def test_negative_unbounded_plus_unbounded(self):
ir = self._make_ir(
"external Foo:\n"
" [requires: -$static_size_in_bits + $static_size_in_bits > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("1", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("-infinity", expr.type.integer.minimum_value)
self.assertEqual("infinity", expr.type.integer.maximum_value)
def test_unbounded_minus_unbounded(self):
ir = self._make_ir(
"external Foo:\n"
" [requires: $static_size_in_bits - $static_size_in_bits > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("1", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("-infinity", expr.type.integer.minimum_value)
self.assertEqual("infinity", expr.type.integer.maximum_value)
def test_unbounded_minus_negative_unbounded(self):
ir = self._make_ir(
"external Foo:\n"
" [requires: $static_size_in_bits - -$static_size_in_bits > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("1", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("0", expr.type.integer.minimum_value)
self.assertEqual("infinity", expr.type.integer.maximum_value)
def test_unbounded_times_constant(self):
ir = self._make_ir("external Foo:\n"
" [requires: ($static_size_in_bits + 1) * 2 > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("2", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("2", expr.type.integer.minimum_value)
self.assertEqual("infinity", expr.type.integer.maximum_value)
def test_unbounded_times_negative_constant(self):
ir = self._make_ir("external Foo:\n"
" [requires: ($static_size_in_bits + 1) * -2 > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("2", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("-infinity", expr.type.integer.minimum_value)
self.assertEqual("-2", expr.type.integer.maximum_value)
def test_unbounded_times_negative_zero(self):
ir = self._make_ir("external Foo:\n"
" [requires: ($static_size_in_bits + 1) * 0 > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("infinity", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("0", expr.type.integer.minimum_value)
self.assertEqual("0", expr.type.integer.maximum_value)
def test_negative_unbounded_times_constant(self):
ir = self._make_ir("external Foo:\n"
" [requires: (-$static_size_in_bits + 1) * 2 > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("2", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("-infinity", expr.type.integer.minimum_value)
self.assertEqual("2", expr.type.integer.maximum_value)
def test_double_unbounded_minus_unbounded(self):
ir = self._make_ir(
"external Foo:\n"
" [requires: 2 * $static_size_in_bits - $static_size_in_bits > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("1", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("-infinity", expr.type.integer.minimum_value)
self.assertEqual("infinity", expr.type.integer.maximum_value)
def test_double_unbounded_times_negative_unbounded(self):
ir = self._make_ir(
"external Foo:\n"
" [requires: 2 * $static_size_in_bits * -$static_size_in_bits > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("2", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("-infinity", expr.type.integer.minimum_value)
self.assertEqual("0", expr.type.integer.maximum_value)
def test_upper_bound_of_field(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] Int x\n"
" let u = $upper_bound(x)\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
u_type = ir.module[0].type[0].structure.field[1].read_transform.type
self.assertEqual("infinity", u_type.integer.modulus)
self.assertEqual("127", u_type.integer.maximum_value)
self.assertEqual("127", u_type.integer.minimum_value)
self.assertEqual("127", u_type.integer.modular_value)
def test_lower_bound_of_field(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] Int x\n"
" let l = $lower_bound(x)\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
l_type = ir.module[0].type[0].structure.field[1].read_transform.type
self.assertEqual("infinity", l_type.integer.modulus)
self.assertEqual("-128", l_type.integer.maximum_value)
self.assertEqual("-128", l_type.integer.minimum_value)
self.assertEqual("-128", l_type.integer.modular_value)
def test_upper_bound_of_max(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] Int x\n"
" 1 [+1] UInt y\n"
" let u = $upper_bound($max(x, y))\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
u_type = ir.module[0].type[0].structure.field[2].read_transform.type
self.assertEqual("infinity", u_type.integer.modulus)
self.assertEqual("255", u_type.integer.maximum_value)
self.assertEqual("255", u_type.integer.minimum_value)
self.assertEqual("255", u_type.integer.modular_value)
def test_lower_bound_of_max(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] Int x\n"
" 1 [+1] UInt y\n"
" let l = $lower_bound($max(x, y))\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
l_type = ir.module[0].type[0].structure.field[2].read_transform.type
self.assertEqual("infinity", l_type.integer.modulus)
self.assertEqual("0", l_type.integer.maximum_value)
self.assertEqual("0", l_type.integer.minimum_value)
self.assertEqual("0", l_type.integer.modular_value)
def test_double_unbounded_both_ends_times_negative_unbounded(self):
ir = self._make_ir(
"external Foo:\n"
" [requires: (2 * ($static_size_in_bits - $static_size_in_bits) + 1) "
" * -$static_size_in_bits > 0]\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].attribute[0].value.expression.function.args[0]
self.assertEqual("1", expr.type.integer.modulus)
self.assertEqual("0", expr.type.integer.modular_value)
self.assertEqual("-infinity", expr.type.integer.minimum_value)
self.assertEqual("infinity", expr.type.integer.maximum_value)
def test_choice_two_non_constant_integers(self):
cases = [
# t % 12 == 7 and f % 20 == 15 ==> r % 4 == 3
(12, 7, 20, 15, 4, 3, -128 * 20 + 15, 127 * 20 + 15),
# t % 24 == 15 and f % 12 == 7 ==> r % 4 == 3
(24, 15, 12, 7, 4, 3, -128 * 24 + 15, 127 * 24 + 15),
# t % 20 == 15 and f % 20 == 10 ==> r % 5 == 0
(20, 15, 20, 10, 5, 0, -128 * 20 + 10, 127 * 20 + 15),
# t % 20 == 16 and f % 20 == 11 ==> r % 5 == 1
(20, 16, 20, 11, 5, 1, -128 * 20 + 11, 127 * 20 + 16),
]
for (t_mod, t_val, f_mod, f_val, r_mod, r_val, r_min, r_max) in cases:
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] Int y\n"
" if (x == 0 ? y * {} + {} : y * {} + {}) == 0:\n"
" 1 [+1] UInt z\n".format(
t_mod, t_val, f_mod, f_val))
self.assertEqual([], expression_bounds.compute_constants(ir))
field = ir.module[0].type[0].structure.field[2]
expr = field.existence_condition.function.args[0]
self.assertEqual(str(r_mod), expr.type.integer.modulus)
self.assertEqual(str(r_val), expr.type.integer.modular_value)
self.assertEqual(str(r_min), expr.type.integer.minimum_value)
self.assertEqual(str(r_max), expr.type.integer.maximum_value)
def test_choice_one_non_constant_integer(self):
cases = [
# t == 35 and f % 20 == 15 ==> res % 20 == 15
(35, 20, 15, 20, 15, -128 * 20 + 15, 127 * 20 + 15),
# t == 200035 and f % 20 == 15 ==> res % 20 == 15
(200035, 20, 15, 20, 15, -128 * 20 + 15, 200035),
# t == 21 and f % 20 == 16 ==> res % 5 == 1
(21, 20, 16, 5, 1, -128 * 20 + 16, 127 * 20 + 16),
]
for (t_val, f_mod, f_val, r_mod, r_val, r_min, r_max) in cases:
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] Int y\n"
" if (x == 0 ? {0} : y * {1} + {2}) == 0:\n"
" 1 [+1] UInt z\n"
" if (x == 0 ? y * {1} + {2} : {0}) == 0:\n"
" 1 [+1] UInt q\n".format(t_val, f_mod, f_val))
self.assertEqual([], expression_bounds.compute_constants(ir))
field_constant_true = ir.module[0].type[0].structure.field[2]
constant_true = field_constant_true.existence_condition.function.args[0]
field_constant_false = ir.module[0].type[0].structure.field[3]
constant_false = field_constant_false.existence_condition.function.args[0]
self.assertEqual(str(r_mod), constant_true.type.integer.modulus)
self.assertEqual(str(r_val), constant_true.type.integer.modular_value)
self.assertEqual(str(r_min), constant_true.type.integer.minimum_value)
self.assertEqual(str(r_max), constant_true.type.integer.maximum_value)
self.assertEqual(str(r_mod), constant_false.type.integer.modulus)
self.assertEqual(str(r_val), constant_false.type.integer.modular_value)
self.assertEqual(str(r_min), constant_false.type.integer.minimum_value)
self.assertEqual(str(r_max), constant_false.type.integer.maximum_value)
def test_choice_two_constant_integers(self):
cases = [
# t == 10 and f == 7 ==> res % 3 == 1
(10, 7, 3, 1, 7, 10),
# t == 4 and f == 4 ==> res == 4
(4, 4, "infinity", 4, 4, 4),
]
for (t_val, f_val, r_mod, r_val, r_min, r_max) in cases:
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] Int y\n"
" if (x == 0 ? {} : {}) == 0:\n"
" 1 [+1] UInt z\n".format(t_val, f_val))
self.assertEqual([], expression_bounds.compute_constants(ir))
field_constant_true = ir.module[0].type[0].structure.field[2]
constant_true = field_constant_true.existence_condition.function.args[0]
self.assertEqual(str(r_mod), constant_true.type.integer.modulus)
self.assertEqual(str(r_val), constant_true.type.integer.modular_value)
self.assertEqual(str(r_min), constant_true.type.integer.minimum_value)
self.assertEqual(str(r_max), constant_true.type.integer.maximum_value)
def test_constant_true_has(self):
ir = self._make_ir("struct Foo:\n"
" if $present(x):\n"
" 1 [+1] UInt q\n"
" 0 [+1] UInt x\n"
" if x > 10:\n"
" 1 [+1] Int y\n"
" if false:\n"
" 2 [+1] Int z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field = ir.module[0].type[0].structure.field[0]
has_func = field.existence_condition
self.assertTrue(has_func.type.boolean.value)
def test_constant_false_has(self):
ir = self._make_ir("struct Foo:\n"
" if $present(z):\n"
" 1 [+1] UInt q\n"
" 0 [+1] UInt x\n"
" if x > 10:\n"
" 1 [+1] Int y\n"
" if false:\n"
" 2 [+1] Int z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field = ir.module[0].type[0].structure.field[0]
has_func = field.existence_condition
self.assertTrue(has_func.type.boolean.HasField("value"))
self.assertFalse(has_func.type.boolean.value)
def test_variable_has(self):
ir = self._make_ir("struct Foo:\n"
" if $present(y):\n"
" 1 [+1] UInt q\n"
" 0 [+1] UInt x\n"
" if x > 10:\n"
" 1 [+1] Int y\n"
" if false:\n"
" 2 [+1] Int z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field = ir.module[0].type[0].structure.field[0]
has_func = field.existence_condition
self.assertFalse(has_func.type.boolean.HasField("value"))
def test_max_of_constants(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] Int y\n"
" if $max(0, 1, 2) == 0:\n"
" 1 [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field = ir.module[0].type[0].structure.field[2]
max_func = field.existence_condition.function.args[0]
self.assertEqual("infinity", max_func.type.integer.modulus)
self.assertEqual("2", max_func.type.integer.modular_value)
self.assertEqual("2", max_func.type.integer.minimum_value)
self.assertEqual("2", max_func.type.integer.maximum_value)
def test_max_dominated_by_constant(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] Int y\n"
" if $max(x, y, 255) == 0:\n"
" 1 [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field = ir.module[0].type[0].structure.field[2]
max_func = field.existence_condition.function.args[0]
self.assertEqual("infinity", max_func.type.integer.modulus)
self.assertEqual("255", max_func.type.integer.modular_value)
self.assertEqual("255", max_func.type.integer.minimum_value)
self.assertEqual("255", max_func.type.integer.maximum_value)
def test_max_of_variables(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] Int y\n"
" if $max(x, y) == 0:\n"
" 1 [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field = ir.module[0].type[0].structure.field[2]
max_func = field.existence_condition.function.args[0]
self.assertEqual("1", max_func.type.integer.modulus)
self.assertEqual("0", max_func.type.integer.modular_value)
self.assertEqual("0", max_func.type.integer.minimum_value)
self.assertEqual("255", max_func.type.integer.maximum_value)
def test_max_of_variables_with_shared_modulus(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] Int y\n"
" if $max(x * 8 + 5, y * 4 + 3) == 0:\n"
" 1 [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field = ir.module[0].type[0].structure.field[2]
max_func = field.existence_condition.function.args[0]
self.assertEqual("2", max_func.type.integer.modulus)
self.assertEqual("1", max_func.type.integer.modular_value)
self.assertEqual("5", max_func.type.integer.minimum_value)
self.assertEqual("2045", max_func.type.integer.maximum_value)
def test_max_of_three_variables(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] Int y\n"
" 2 [+2] Int z\n"
" if $max(x, y, z) == 0:\n"
" 1 [+1] UInt q\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field = ir.module[0].type[0].structure.field[3]
max_func = field.existence_condition.function.args[0]
self.assertEqual("1", max_func.type.integer.modulus)
self.assertEqual("0", max_func.type.integer.modular_value)
self.assertEqual("0", max_func.type.integer.minimum_value)
self.assertEqual("32767", max_func.type.integer.maximum_value)
def test_max_of_one_variable(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] Int y\n"
" 2 [+2] Int z\n"
" if $max(x * 2 + 3) == 0:\n"
" 1 [+1] UInt q\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field = ir.module[0].type[0].structure.field[3]
max_func = field.existence_condition.function.args[0]
self.assertEqual("2", max_func.type.integer.modulus)
self.assertEqual("1", max_func.type.integer.modular_value)
self.assertEqual("3", max_func.type.integer.minimum_value)
self.assertEqual("513", max_func.type.integer.maximum_value)
def test_max_of_one_variable_and_one_constant(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+1] Int y\n"
" 2 [+2] Int z\n"
" if $max(x * 2 + 3, 311) == 0:\n"
" 1 [+1] UInt q\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field = ir.module[0].type[0].structure.field[3]
max_func = field.existence_condition.function.args[0]
self.assertEqual("2", max_func.type.integer.modulus)
self.assertEqual("1", max_func.type.integer.modular_value)
self.assertEqual("311", max_func.type.integer.minimum_value)
self.assertEqual("513", max_func.type.integer.maximum_value)
def test_choice_non_integer_arguments(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" if x == 0 ? false : true:\n"
" 1 [+1] UInt y\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
expr = ir.module[0].type[0].structure.field[1].existence_condition
self.assertEqual("boolean", expr.type.WhichOneof("type"))
self.assertFalse(expr.type.boolean.HasField("value"))
def test_uint_value_range_for_explicit_size(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" 1 [+x] UInt:16 y\n"
" y [+1] UInt z\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("1", z_start.type.integer.modulus)
self.assertEqual("0", z_start.type.integer.modular_value)
self.assertEqual("0", z_start.type.integer.minimum_value)
self.assertEqual("65535", z_start.type.integer.maximum_value)
def test_uint_value_ranges(self):
cases = [
(1, 1),
(2, 3),
(3, 7),
(4, 15),
(8, 255),
(12, 4095),
(15, 32767),
(16, 65535),
(32, 4294967295),
(48, 281474976710655),
(64, 18446744073709551615),
]
for bits, upper in cases:
ir = self._make_ir("struct Foo:\n"
" 0 [+8] bits:\n"
" 0 [+{}] UInt x\n"
" x [+1] UInt z\n".format(bits))
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("1", z_start.type.integer.modulus)
self.assertEqual("0", z_start.type.integer.modular_value)
self.assertEqual("0", z_start.type.integer.minimum_value)
self.assertEqual(str(upper), z_start.type.integer.maximum_value)
def test_int_value_ranges(self):
cases = [
(1, -1, 0),
(2, -2, 1),
(3, -4, 3),
(4, -8, 7),
(8, -128, 127),
(12, -2048, 2047),
(15, -16384, 16383),
(16, -32768, 32767),
(32, -2147483648, 2147483647),
(48, -140737488355328, 140737488355327),
(64, -9223372036854775808, 9223372036854775807),
]
for bits, lower, upper in cases:
ir = self._make_ir("struct Foo:\n"
" 0 [+8] bits:\n"
" 0 [+{}] Int x\n"
" x [+1] UInt z\n".format(bits))
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("1", z_start.type.integer.modulus)
self.assertEqual("0", z_start.type.integer.modular_value)
self.assertEqual(str(lower), z_start.type.integer.minimum_value)
self.assertEqual(str(upper), z_start.type.integer.maximum_value)
def test_bcd_value_ranges(self):
cases = [
(1, 1),
(2, 3),
(3, 7),
(4, 9),
(8, 99),
(12, 999),
(15, 7999),
(16, 9999),
(32, 99999999),
(48, 999999999999),
(64, 9999999999999999),
]
for bits, upper in cases:
ir = self._make_ir("struct Foo:\n"
" 0 [+8] bits:\n"
" 0 [+{}] Bcd x\n"
" x [+1] UInt z\n".format(bits))
self.assertEqual([], expression_bounds.compute_constants(ir))
z_start = ir.module[0].type[0].structure.field[2].location.start
self.assertEqual("1", z_start.type.integer.modulus)
self.assertEqual("0", z_start.type.integer.modular_value)
self.assertEqual("0", z_start.type.integer.minimum_value)
self.assertEqual(str(upper), z_start.type.integer.maximum_value)
def test_virtual_field_bounds(self):
ir = self._make_ir("struct Foo:\n"
" 0 [+1] UInt x\n"
" let y = x + 10\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field_y = ir.module[0].type[0].structure.field[1]
self.assertEqual("1", field_y.read_transform.type.integer.modulus)
self.assertEqual("0", field_y.read_transform.type.integer.modular_value)
self.assertEqual("10", field_y.read_transform.type.integer.minimum_value)
self.assertEqual("265", field_y.read_transform.type.integer.maximum_value)
def test_virtual_field_bounds_copied(self):
ir = self._make_ir("struct Foo:\n"
" let z = y + 100\n"
" let y = x + 10\n"
" 0 [+1] UInt x\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field_z = ir.module[0].type[0].structure.field[0]
self.assertEqual("1", field_z.read_transform.type.integer.modulus)
self.assertEqual("0", field_z.read_transform.type.integer.modular_value)
self.assertEqual("110", field_z.read_transform.type.integer.minimum_value)
self.assertEqual("365", field_z.read_transform.type.integer.maximum_value)
y_reference = field_z.read_transform.function.args[0]
self.assertEqual("1", y_reference.type.integer.modulus)
self.assertEqual("0", y_reference.type.integer.modular_value)
self.assertEqual("10", y_reference.type.integer.minimum_value)
self.assertEqual("265", y_reference.type.integer.maximum_value)
def test_constant_reference_to_virtual_bounds_copied(self):
ir = self._make_ir("struct Foo:\n"
" let ten = Bar.ten\n"
" let truth = Bar.truth\n"
"struct Bar:\n"
" let ten = 10\n"
" let truth = true\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field_ten = ir.module[0].type[0].structure.field[0]
self.assertEqual("infinity", field_ten.read_transform.type.integer.modulus)
self.assertEqual("10", field_ten.read_transform.type.integer.modular_value)
self.assertEqual("10", field_ten.read_transform.type.integer.minimum_value)
self.assertEqual("10", field_ten.read_transform.type.integer.maximum_value)
field_truth = ir.module[0].type[0].structure.field[1]
self.assertTrue(field_truth.read_transform.type.boolean.value)
def test_forward_reference_to_reference_to_enum_correctly_calculated(self):
ir = self._make_ir("struct Foo:\n"
" let ten = Bar.TEN\n"
"enum Bar:\n"
" TEN = TEN2\n"
" TEN2 = 5 + 5\n")
self.assertEqual([], expression_bounds.compute_constants(ir))
field_ten = ir.module[0].type[0].structure.field[0]
self.assertEqual("10", field_ten.read_transform.type.enumeration.value)
class InfinityAugmentedArithmeticTest(unittest.TestCase):
# TODO(bolms): Will there ever be any situations where all elements of the arg
# to _min would be "infinity"?
def test_min_of_infinities(self):
self.assertEqual("infinity",
expression_bounds._min(["infinity", "infinity"]))
# TODO(bolms): Will there ever be any situations where all elements of the arg
# to _max would be "-infinity"?
def test_max_of_negative_infinities(self):
self.assertEqual("-infinity",
expression_bounds._max(["-infinity", "-infinity"]))
def test_shared_modular_value_of_identical_modulus_and_value(self):
self.assertEqual((10, 8),
expression_bounds._shared_modular_value((10, 8), (10, 8)))
def test_shared_modular_value_of_identical_modulus(self):
self.assertEqual((5, 3),
expression_bounds._shared_modular_value((10, 8), (10, 3)))
def test_shared_modular_value_of_identical_value(self):
self.assertEqual((6, 2),
expression_bounds._shared_modular_value((18, 2), (12, 2)))
def test_shared_modular_value_of_different_arguments(self):
self.assertEqual((7, 4),
expression_bounds._shared_modular_value((21, 11), (14, 4)))
def test_shared_modular_value_of_infinity_and_non(self):
self.assertEqual((7, 4),
expression_bounds._shared_modular_value(("infinity", 25),
(14, 4)))
def test_shared_modular_value_of_infinity_and_infinity(self):
self.assertEqual((14, 5),
expression_bounds._shared_modular_value(("infinity", 19),
("infinity", 5)))
def test_shared_modular_value_of_infinity_and_identical_value(self):
self.assertEqual(("infinity", 5),
expression_bounds._shared_modular_value(("infinity", 5),
("infinity", 5)))
if __name__ == "__main__":
unittest.main()