| # 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() |