xref: /aosp_15_r20/external/emboss/compiler/front_end/write_inference_test.py (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1# Copyright 2019 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Tests for ...emboss.front_end.write_inference."""
16
17import unittest
18from compiler.front_end import glue
19from compiler.front_end import write_inference
20from compiler.util import ir_data
21from compiler.util import test_util
22
23
24class WriteInferenceTest(unittest.TestCase):
25
26  def _make_ir(self, emb_text):
27    ir, unused_debug_info, errors = glue.parse_emboss_file(
28        "m.emb",
29        test_util.dict_file_reader({"m.emb": emb_text}),
30        stop_before_step="set_write_methods")
31    assert not errors, errors
32    return ir
33
34  def test_adds_physical_write_method(self):
35    ir = self._make_ir("struct Foo:\n"
36                       "  0 [+1]  UInt  x\n")
37    self.assertEqual([], write_inference.set_write_methods(ir))
38    self.assertTrue(
39        ir.module[0].type[0].structure.field[0].write_method.physical)
40
41  def test_adds_read_only_write_method_to_non_alias_virtual(self):
42    ir = self._make_ir("struct Foo:\n"
43                       "  let x = 5\n")
44    self.assertEqual([], write_inference.set_write_methods(ir))
45    self.assertTrue(
46        ir.module[0].type[0].structure.field[0].write_method.read_only)
47
48  def test_adds_alias_write_method_to_alias_of_physical_field(self):
49    ir = self._make_ir("struct Foo:\n"
50                       "  let x = y\n"
51                       "  0 [+1]  UInt  y\n")
52    self.assertEqual([], write_inference.set_write_methods(ir))
53    field = ir.module[0].type[0].structure.field[0]
54    self.assertTrue(field.write_method.HasField("alias"))
55    self.assertEqual(
56        "y", field.write_method.alias.path[0].canonical_name.object_path[-1])
57
58  def test_adds_alias_write_method_to_alias_of_alias_of_physical_field(self):
59    ir = self._make_ir("struct Foo:\n"
60                       "  let x = z\n"
61                       "  let z = y\n"
62                       "  0 [+1]  UInt  y\n")
63    self.assertEqual([], write_inference.set_write_methods(ir))
64    field = ir.module[0].type[0].structure.field[0]
65    self.assertTrue(field.write_method.HasField("alias"))
66    self.assertEqual(
67        "z", field.write_method.alias.path[0].canonical_name.object_path[-1])
68
69  def test_adds_read_only_write_method_to_alias_of_read_only(self):
70    ir = self._make_ir("struct Foo:\n"
71                       "  let x = y\n"
72                       "  let y = 5\n")
73    self.assertEqual([], write_inference.set_write_methods(ir))
74    field = ir.module[0].type[0].structure.field[0]
75    self.assertTrue(field.write_method.read_only)
76
77  def test_adds_read_only_write_method_to_alias_of_alias_of_read_only(self):
78    ir = self._make_ir("struct Foo:\n"
79                       "  let x = z\n"
80                       "  let z = y\n"
81                       "  let y = 5\n")
82    self.assertEqual([], write_inference.set_write_methods(ir))
83    field = ir.module[0].type[0].structure.field[0]
84    self.assertTrue(field.write_method.read_only)
85
86  def test_adds_read_only_write_method_to_alias_of_parameter(self):
87    ir = self._make_ir("struct Foo(x: UInt:8):\n"
88                       "  let y = x\n")
89    self.assertEqual([], write_inference.set_write_methods(ir))
90    field = ir.module[0].type[0].structure.field[0]
91    self.assertTrue(field.write_method.read_only)
92
93  def test_adds_transform_write_method_to_base_value_field(self):
94    ir = self._make_ir("struct Foo:\n"
95                       "  0 [+1]  UInt  x\n"
96                       "  let y = x + 50\n")
97    self.assertEqual([], write_inference.set_write_methods(ir))
98    field = ir.module[0].type[0].structure.field[1]
99    transform = field.write_method.transform
100    self.assertTrue(transform)
101    self.assertEqual(
102        "x",
103        transform.destination.path[0].canonical_name.object_path[-1])
104    self.assertEqual(ir_data.FunctionMapping.SUBTRACTION,
105                     transform.function_body.function.function)
106    arg0, arg1 = transform.function_body.function.args
107    self.assertEqual("$logical_value",
108                     arg0.builtin_reference.canonical_name.object_path[0])
109    self.assertEqual("50", arg1.constant.value)
110
111  def test_adds_transform_write_method_to_negative_base_value_field(self):
112    ir = self._make_ir("struct Foo:\n"
113                       "  0 [+1]  UInt  x\n"
114                       "  let y = x - 50\n")
115    self.assertEqual([], write_inference.set_write_methods(ir))
116    field = ir.module[0].type[0].structure.field[1]
117    transform = field.write_method.transform
118    self.assertTrue(transform)
119    self.assertEqual(
120        "x",
121        transform.destination.path[0].canonical_name.object_path[-1])
122    self.assertEqual(ir_data.FunctionMapping.ADDITION,
123                     transform.function_body.function.function)
124    arg0, arg1 = transform.function_body.function.args
125    self.assertEqual("$logical_value",
126                     arg0.builtin_reference.canonical_name.object_path[0])
127    self.assertEqual("50", arg1.constant.value)
128
129  def test_adds_transform_write_method_to_reversed_base_value_field(self):
130    ir = self._make_ir("struct Foo:\n"
131                       "  0 [+1]  UInt  x\n"
132                       "  let y = 50 + x\n")
133    self.assertEqual([], write_inference.set_write_methods(ir))
134    field = ir.module[0].type[0].structure.field[1]
135    transform = field.write_method.transform
136    self.assertTrue(transform)
137    self.assertEqual(
138        "x",
139        transform.destination.path[0].canonical_name.object_path[-1])
140    self.assertEqual(ir_data.FunctionMapping.SUBTRACTION,
141                     transform.function_body.function.function)
142    arg0, arg1 = transform.function_body.function.args
143    self.assertEqual("$logical_value",
144                     arg0.builtin_reference.canonical_name.object_path[0])
145    self.assertEqual("50", arg1.constant.value)
146
147  def test_adds_transform_write_method_to_reversed_negative_base_value_field(
148      self):
149    ir = self._make_ir("struct Foo:\n"
150                       "  0 [+1]  UInt  x\n"
151                       "  let y = 50 - x\n")
152    self.assertEqual([], write_inference.set_write_methods(ir))
153    field = ir.module[0].type[0].structure.field[1]
154    transform = field.write_method.transform
155    self.assertTrue(transform)
156    self.assertEqual(
157        "x",
158        transform.destination.path[0].canonical_name.object_path[-1])
159    self.assertEqual(ir_data.FunctionMapping.SUBTRACTION,
160                     transform.function_body.function.function)
161    arg0, arg1 = transform.function_body.function.args
162    self.assertEqual("50", arg0.constant.value)
163    self.assertEqual("$logical_value",
164                     arg1.builtin_reference.canonical_name.object_path[0])
165
166  def test_adds_transform_write_method_to_nested_invertible_field(self):
167    ir = self._make_ir("struct Foo:\n"
168                       "  0 [+1]  UInt  x\n"
169                       "  let y = 30 + (50 - x)\n")
170    self.assertEqual([], write_inference.set_write_methods(ir))
171    field = ir.module[0].type[0].structure.field[1]
172    transform = field.write_method.transform
173    self.assertTrue(transform)
174    self.assertEqual(
175        "x",
176        transform.destination.path[0].canonical_name.object_path[-1])
177    self.assertEqual(ir_data.FunctionMapping.SUBTRACTION,
178                     transform.function_body.function.function)
179    arg0, arg1 = transform.function_body.function.args
180    self.assertEqual("50", arg0.constant.value)
181    self.assertEqual(ir_data.FunctionMapping.SUBTRACTION, arg1.function.function)
182    arg10, arg11 = arg1.function.args
183    self.assertEqual("$logical_value",
184                     arg10.builtin_reference.canonical_name.object_path[0])
185    self.assertEqual("30", arg11.constant.value)
186
187  def test_does_not_add_transform_write_method_for_parameter_target(self):
188    ir = self._make_ir("struct Foo(x: UInt:8):\n"
189                       "  let y = 50 + x\n")
190    self.assertEqual([], write_inference.set_write_methods(ir))
191    field = ir.module[0].type[0].structure.field[0]
192    self.assertEqual("read_only", field.write_method.WhichOneof("method"))
193
194  def test_adds_transform_write_method_with_complex_auxiliary_subexpression(
195      self):
196    ir = self._make_ir("struct Foo:\n"
197                       "  0 [+1]  UInt  x\n"
198                       "  let y = x - $max(Foo.$size_in_bytes, Foo.z)\n"
199                       "  let z = 500\n")
200    self.assertEqual([], write_inference.set_write_methods(ir))
201    field = ir.module[0].type[0].structure.field[1]
202    transform = field.write_method.transform
203    self.assertTrue(transform)
204    self.assertEqual(
205        "x",
206        transform.destination.path[0].canonical_name.object_path[-1])
207    self.assertEqual(ir_data.FunctionMapping.ADDITION,
208                     transform.function_body.function.function)
209    args = transform.function_body.function.args
210    self.assertEqual("$logical_value",
211                     args[0].builtin_reference.canonical_name.object_path[0])
212    self.assertEqual(field.read_transform.function.args[1], args[1])
213
214
215if __name__ == "__main__":
216  unittest.main()
217