xref: /aosp_15_r20/external/emboss/compiler/front_end/synthetics_test.py (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1*99e0aae7SDavid Rees# Copyright 2019 Google LLC
2*99e0aae7SDavid Rees#
3*99e0aae7SDavid Rees# Licensed under the Apache License, Version 2.0 (the "License");
4*99e0aae7SDavid Rees# you may not use this file except in compliance with the License.
5*99e0aae7SDavid Rees# You may obtain a copy of the License at
6*99e0aae7SDavid Rees#
7*99e0aae7SDavid Rees#     https://www.apache.org/licenses/LICENSE-2.0
8*99e0aae7SDavid Rees#
9*99e0aae7SDavid Rees# Unless required by applicable law or agreed to in writing, software
10*99e0aae7SDavid Rees# distributed under the License is distributed on an "AS IS" BASIS,
11*99e0aae7SDavid Rees# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*99e0aae7SDavid Rees# See the License for the specific language governing permissions and
13*99e0aae7SDavid Rees# limitations under the License.
14*99e0aae7SDavid Rees
15*99e0aae7SDavid Rees"""Tests for front_end.synthetics."""
16*99e0aae7SDavid Rees
17*99e0aae7SDavid Reesimport unittest
18*99e0aae7SDavid Reesfrom compiler.front_end import glue
19*99e0aae7SDavid Reesfrom compiler.front_end import synthetics
20*99e0aae7SDavid Reesfrom compiler.util import error
21*99e0aae7SDavid Reesfrom compiler.util import ir_data
22*99e0aae7SDavid Reesfrom compiler.util import test_util
23*99e0aae7SDavid Rees
24*99e0aae7SDavid Rees
25*99e0aae7SDavid Reesclass SyntheticsTest(unittest.TestCase):
26*99e0aae7SDavid Rees
27*99e0aae7SDavid Rees  def _find_attribute(self, field, name):
28*99e0aae7SDavid Rees    result = None
29*99e0aae7SDavid Rees    for attribute in field.attribute:
30*99e0aae7SDavid Rees      if attribute.name.text == name:
31*99e0aae7SDavid Rees        self.assertIsNone(result)
32*99e0aae7SDavid Rees        result = attribute
33*99e0aae7SDavid Rees    self.assertIsNotNone(result)
34*99e0aae7SDavid Rees    return result
35*99e0aae7SDavid Rees
36*99e0aae7SDavid Rees  def _make_ir(self, emb_text):
37*99e0aae7SDavid Rees    ir, unused_debug_info, errors = glue.parse_emboss_file(
38*99e0aae7SDavid Rees        "m.emb",
39*99e0aae7SDavid Rees        test_util.dict_file_reader({"m.emb": emb_text}),
40*99e0aae7SDavid Rees        stop_before_step="desugar")
41*99e0aae7SDavid Rees    assert not errors, errors
42*99e0aae7SDavid Rees    return ir
43*99e0aae7SDavid Rees
44*99e0aae7SDavid Rees  def test_nothing_to_do(self):
45*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
46*99e0aae7SDavid Rees                       "  0 [+1]     UInt      x\n"
47*99e0aae7SDavid Rees                       "  1 [+1]     UInt:8[]  y\n")
48*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
49*99e0aae7SDavid Rees
50*99e0aae7SDavid Rees  def test_adds_anonymous_bits_fields(self):
51*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
52*99e0aae7SDavid Rees                       "  0 [+1]  bits:\n"
53*99e0aae7SDavid Rees                       "    0 [+4]  Bar   bar\n"
54*99e0aae7SDavid Rees                       "    4 [+4]  UInt  uint\n"
55*99e0aae7SDavid Rees                       "  1 [+1]  bits:\n"
56*99e0aae7SDavid Rees                       "    0 [+4]  Bits  nested_bits\n"
57*99e0aae7SDavid Rees                       "enum Bar:\n"
58*99e0aae7SDavid Rees                       "  BAR = 0\n"
59*99e0aae7SDavid Rees                       "bits Bits:\n"
60*99e0aae7SDavid Rees                       "  0 [+4]  UInt  uint\n")
61*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
62*99e0aae7SDavid Rees    structure = ir.module[0].type[0].structure
63*99e0aae7SDavid Rees    # The first field should be the anonymous bits structure.
64*99e0aae7SDavid Rees    self.assertTrue(structure.field[0].HasField("location"))
65*99e0aae7SDavid Rees    # Then the aliases generated for those structures.
66*99e0aae7SDavid Rees    self.assertEqual("bar", structure.field[1].name.name.text)
67*99e0aae7SDavid Rees    self.assertEqual("uint", structure.field[2].name.name.text)
68*99e0aae7SDavid Rees    # Then the second anonymous bits.
69*99e0aae7SDavid Rees    self.assertTrue(structure.field[3].HasField("location"))
70*99e0aae7SDavid Rees    # Then the alias from the second anonymous bits.
71*99e0aae7SDavid Rees    self.assertEqual("nested_bits", structure.field[4].name.name.text)
72*99e0aae7SDavid Rees
73*99e0aae7SDavid Rees  def test_adds_correct_existence_condition(self):
74*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
75*99e0aae7SDavid Rees                       "  0 [+1]  bits:\n"
76*99e0aae7SDavid Rees                       "    0 [+4]  UInt  bar\n")
77*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
78*99e0aae7SDavid Rees    bits_field = ir.module[0].type[0].structure.field[0]
79*99e0aae7SDavid Rees    alias_field = ir.module[0].type[0].structure.field[1]
80*99e0aae7SDavid Rees    self.assertEqual("bar", alias_field.name.name.text)
81*99e0aae7SDavid Rees    self.assertEqual(bits_field.name.name.text,
82*99e0aae7SDavid Rees                     alias_field.existence_condition.function.args[0].function.
83*99e0aae7SDavid Rees                     args[0].field_reference.path[0].source_name[-1].text)
84*99e0aae7SDavid Rees    self.assertEqual(bits_field.name.name.text,
85*99e0aae7SDavid Rees                     alias_field.existence_condition.function.args[1].function.
86*99e0aae7SDavid Rees                     args[0].field_reference.path[0].source_name[-1].text)
87*99e0aae7SDavid Rees    self.assertEqual("bar",
88*99e0aae7SDavid Rees                     alias_field.existence_condition.function.args[1].function.
89*99e0aae7SDavid Rees                     args[0].field_reference.path[1].source_name[-1].text)
90*99e0aae7SDavid Rees    self.assertEqual(
91*99e0aae7SDavid Rees        ir_data.FunctionMapping.PRESENCE,
92*99e0aae7SDavid Rees        alias_field.existence_condition.function.args[0].function.function)
93*99e0aae7SDavid Rees    self.assertEqual(
94*99e0aae7SDavid Rees        ir_data.FunctionMapping.PRESENCE,
95*99e0aae7SDavid Rees        alias_field.existence_condition.function.args[1].function.function)
96*99e0aae7SDavid Rees    self.assertEqual(ir_data.FunctionMapping.AND,
97*99e0aae7SDavid Rees                     alias_field.existence_condition.function.function)
98*99e0aae7SDavid Rees
99*99e0aae7SDavid Rees  def test_adds_correct_read_transform(self):
100*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
101*99e0aae7SDavid Rees                       "  0 [+1]  bits:\n"
102*99e0aae7SDavid Rees                       "    0 [+4]  UInt  bar\n")
103*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
104*99e0aae7SDavid Rees    bits_field = ir.module[0].type[0].structure.field[0]
105*99e0aae7SDavid Rees    alias_field = ir.module[0].type[0].structure.field[1]
106*99e0aae7SDavid Rees    self.assertEqual("bar", alias_field.name.name.text)
107*99e0aae7SDavid Rees    self.assertEqual(
108*99e0aae7SDavid Rees        bits_field.name.name.text,
109*99e0aae7SDavid Rees        alias_field.read_transform.field_reference.path[0].source_name[-1].text)
110*99e0aae7SDavid Rees    self.assertEqual(
111*99e0aae7SDavid Rees        "bar",
112*99e0aae7SDavid Rees        alias_field.read_transform.field_reference.path[1].source_name[-1].text)
113*99e0aae7SDavid Rees
114*99e0aae7SDavid Rees  def test_adds_correct_abbreviation(self):
115*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
116*99e0aae7SDavid Rees                       "  0 [+1]  bits:\n"
117*99e0aae7SDavid Rees                       "    0 [+4]  UInt  bar\n"
118*99e0aae7SDavid Rees                       "    4 [+4]  UInt  baz (qux)\n")
119*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
120*99e0aae7SDavid Rees    bar_alias = ir.module[0].type[0].structure.field[1]
121*99e0aae7SDavid Rees    baz_alias = ir.module[0].type[0].structure.field[2]
122*99e0aae7SDavid Rees    self.assertFalse(bar_alias.HasField("abbreviation"))
123*99e0aae7SDavid Rees    self.assertEqual("qux", baz_alias.abbreviation.text)
124*99e0aae7SDavid Rees
125*99e0aae7SDavid Rees  def test_anonymous_bits_sets_correct_is_synthetic(self):
126*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
127*99e0aae7SDavid Rees                       "  0 [+1]  bits:\n"
128*99e0aae7SDavid Rees                       "    0 [+4]  UInt  bar (b)\n")
129*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
130*99e0aae7SDavid Rees    bits_field = ir.module[0].type[0].subtype[0].structure.field[0]
131*99e0aae7SDavid Rees    alias_field = ir.module[0].type[0].structure.field[1]
132*99e0aae7SDavid Rees    self.assertFalse(alias_field.name.source_location.is_synthetic)
133*99e0aae7SDavid Rees    self.assertTrue(alias_field.HasField("abbreviation"))
134*99e0aae7SDavid Rees    self.assertFalse(alias_field.abbreviation.source_location.is_synthetic)
135*99e0aae7SDavid Rees    self.assertTrue(alias_field.HasField("read_transform"))
136*99e0aae7SDavid Rees    read_alias = alias_field.read_transform
137*99e0aae7SDavid Rees    self.assertTrue(read_alias.source_location.is_synthetic)
138*99e0aae7SDavid Rees    self.assertTrue(
139*99e0aae7SDavid Rees        read_alias.field_reference.path[0].source_location.is_synthetic)
140*99e0aae7SDavid Rees    alias_condition = alias_field.existence_condition
141*99e0aae7SDavid Rees    self.assertTrue(alias_condition.source_location.is_synthetic)
142*99e0aae7SDavid Rees    self.assertTrue(
143*99e0aae7SDavid Rees        alias_condition.function.args[0].source_location.is_synthetic)
144*99e0aae7SDavid Rees    self.assertTrue(bits_field.name.source_location.is_synthetic)
145*99e0aae7SDavid Rees    self.assertTrue(bits_field.name.name.source_location.is_synthetic)
146*99e0aae7SDavid Rees    self.assertTrue(bits_field.abbreviation.source_location.is_synthetic)
147*99e0aae7SDavid Rees
148*99e0aae7SDavid Rees  def test_adds_text_output_skip_attribute_to_anonymous_bits(self):
149*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
150*99e0aae7SDavid Rees                       "  0 [+1]  bits:\n"
151*99e0aae7SDavid Rees                       "    0 [+4]  UInt  bar (b)\n")
152*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
153*99e0aae7SDavid Rees    bits_field = ir.module[0].type[0].structure.field[0]
154*99e0aae7SDavid Rees    text_output_attribute = self._find_attribute(bits_field, "text_output")
155*99e0aae7SDavid Rees    self.assertEqual("Skip", text_output_attribute.value.string_constant.text)
156*99e0aae7SDavid Rees
157*99e0aae7SDavid Rees  def test_skip_attribute_is_marked_as_synthetic(self):
158*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
159*99e0aae7SDavid Rees                       "  0 [+1]  bits:\n"
160*99e0aae7SDavid Rees                       "    0 [+4]  UInt  bar\n")
161*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
162*99e0aae7SDavid Rees    bits_field = ir.module[0].type[0].structure.field[0]
163*99e0aae7SDavid Rees    attribute = self._find_attribute(bits_field, "text_output")
164*99e0aae7SDavid Rees    self.assertTrue(attribute.source_location.is_synthetic)
165*99e0aae7SDavid Rees    self.assertTrue(attribute.name.source_location.is_synthetic)
166*99e0aae7SDavid Rees    self.assertTrue(attribute.value.source_location.is_synthetic)
167*99e0aae7SDavid Rees    self.assertTrue(
168*99e0aae7SDavid Rees        attribute.value.string_constant.source_location.is_synthetic)
169*99e0aae7SDavid Rees
170*99e0aae7SDavid Rees  def test_adds_size_in_bytes(self):
171*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
172*99e0aae7SDavid Rees                       "  1 [+l]  UInt:8[]  bytes\n"
173*99e0aae7SDavid Rees                       "  0 [+1]  UInt      length (l)\n")
174*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
175*99e0aae7SDavid Rees    structure = ir.module[0].type[0].structure
176*99e0aae7SDavid Rees    size_in_bytes_field = structure.field[2]
177*99e0aae7SDavid Rees    max_size_in_bytes_field = structure.field[3]
178*99e0aae7SDavid Rees    min_size_in_bytes_field = structure.field[4]
179*99e0aae7SDavid Rees    self.assertEqual("$size_in_bytes", size_in_bytes_field.name.name.text)
180*99e0aae7SDavid Rees    self.assertEqual(ir_data.FunctionMapping.MAXIMUM,
181*99e0aae7SDavid Rees                     size_in_bytes_field.read_transform.function.function)
182*99e0aae7SDavid Rees    self.assertEqual("$max_size_in_bytes",
183*99e0aae7SDavid Rees                     max_size_in_bytes_field.name.name.text)
184*99e0aae7SDavid Rees    self.assertEqual(ir_data.FunctionMapping.UPPER_BOUND,
185*99e0aae7SDavid Rees                     max_size_in_bytes_field.read_transform.function.function)
186*99e0aae7SDavid Rees    self.assertEqual("$min_size_in_bytes",
187*99e0aae7SDavid Rees                     min_size_in_bytes_field.name.name.text)
188*99e0aae7SDavid Rees    self.assertEqual(ir_data.FunctionMapping.LOWER_BOUND,
189*99e0aae7SDavid Rees                     min_size_in_bytes_field.read_transform.function.function)
190*99e0aae7SDavid Rees    # The correctness of $size_in_bytes et al are tested much further down
191*99e0aae7SDavid Rees    # stream, in tests of the generated C++ code.
192*99e0aae7SDavid Rees
193*99e0aae7SDavid Rees  def test_adds_size_in_bits(self):
194*99e0aae7SDavid Rees    ir = self._make_ir("bits Foo:\n"
195*99e0aae7SDavid Rees                       "  1 [+9]  UInt  hi\n"
196*99e0aae7SDavid Rees                       "  0 [+1]  Flag  lo\n")
197*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
198*99e0aae7SDavid Rees    structure = ir.module[0].type[0].structure
199*99e0aae7SDavid Rees    size_in_bits_field = structure.field[2]
200*99e0aae7SDavid Rees    max_size_in_bits_field = structure.field[3]
201*99e0aae7SDavid Rees    min_size_in_bits_field = structure.field[4]
202*99e0aae7SDavid Rees    self.assertEqual("$size_in_bits", size_in_bits_field.name.name.text)
203*99e0aae7SDavid Rees    self.assertEqual(ir_data.FunctionMapping.MAXIMUM,
204*99e0aae7SDavid Rees                     size_in_bits_field.read_transform.function.function)
205*99e0aae7SDavid Rees    self.assertEqual("$max_size_in_bits",
206*99e0aae7SDavid Rees                     max_size_in_bits_field.name.name.text)
207*99e0aae7SDavid Rees    self.assertEqual(ir_data.FunctionMapping.UPPER_BOUND,
208*99e0aae7SDavid Rees                     max_size_in_bits_field.read_transform.function.function)
209*99e0aae7SDavid Rees    self.assertEqual("$min_size_in_bits",
210*99e0aae7SDavid Rees                     min_size_in_bits_field.name.name.text)
211*99e0aae7SDavid Rees    self.assertEqual(ir_data.FunctionMapping.LOWER_BOUND,
212*99e0aae7SDavid Rees                     min_size_in_bits_field.read_transform.function.function)
213*99e0aae7SDavid Rees    # The correctness of $size_in_bits et al are tested much further down
214*99e0aae7SDavid Rees    # stream, in tests of the generated C++ code.
215*99e0aae7SDavid Rees
216*99e0aae7SDavid Rees  def test_adds_text_output_skip_attribute_to_size_in_bytes(self):
217*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
218*99e0aae7SDavid Rees                       "  1 [+l]  UInt:8[]  bytes\n"
219*99e0aae7SDavid Rees                       "  0 [+1]  UInt      length (l)\n")
220*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
221*99e0aae7SDavid Rees    size_in_bytes_field = ir.module[0].type[0].structure.field[2]
222*99e0aae7SDavid Rees    self.assertEqual("$size_in_bytes", size_in_bytes_field.name.name.text)
223*99e0aae7SDavid Rees    text_output_attribute = self._find_attribute(size_in_bytes_field,
224*99e0aae7SDavid Rees                                                 "text_output")
225*99e0aae7SDavid Rees    self.assertEqual("Skip", text_output_attribute.value.string_constant.text)
226*99e0aae7SDavid Rees
227*99e0aae7SDavid Rees  def test_replaces_next(self):
228*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
229*99e0aae7SDavid Rees                       "  1     [+2]  UInt:8[]  a\n"
230*99e0aae7SDavid Rees                       "  $next [+4]  UInt      b\n"
231*99e0aae7SDavid Rees                       "  $next [+1]  UInt      c\n")
232*99e0aae7SDavid Rees    self.assertEqual([], synthetics.desugar(ir))
233*99e0aae7SDavid Rees    offset_of_b = ir.module[0].type[0].structure.field[1].location.start
234*99e0aae7SDavid Rees    self.assertTrue(offset_of_b.HasField("function"))
235*99e0aae7SDavid Rees    self.assertEqual(offset_of_b.function.function, ir_data.FunctionMapping.ADDITION)
236*99e0aae7SDavid Rees    self.assertEqual(offset_of_b.function.args[0].constant.value, "1")
237*99e0aae7SDavid Rees    self.assertEqual(offset_of_b.function.args[1].constant.value, "2")
238*99e0aae7SDavid Rees    offset_of_c = ir.module[0].type[0].structure.field[2].location.start
239*99e0aae7SDavid Rees    self.assertEqual(
240*99e0aae7SDavid Rees            offset_of_c.function.args[0].function.args[0].constant.value, "1")
241*99e0aae7SDavid Rees    self.assertEqual(
242*99e0aae7SDavid Rees            offset_of_c.function.args[0].function.args[1].constant.value, "2")
243*99e0aae7SDavid Rees    self.assertEqual(offset_of_c.function.args[1].constant.value, "4")
244*99e0aae7SDavid Rees
245*99e0aae7SDavid Rees  def test_next_in_first_field(self):
246*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
247*99e0aae7SDavid Rees                       "  $next [+2]  UInt:8[]  a\n"
248*99e0aae7SDavid Rees                       "  $next [+4]  UInt      b\n")
249*99e0aae7SDavid Rees    struct = ir.module[0].type[0].structure
250*99e0aae7SDavid Rees    self.assertEqual([[
251*99e0aae7SDavid Rees        error.error("m.emb", struct.field[0].location.start.source_location,
252*99e0aae7SDavid Rees                    "`$next` may not be used in the first physical field of " +
253*99e0aae7SDavid Rees                    "a structure; perhaps you meant `0`?"),
254*99e0aae7SDavid Rees    ]], synthetics.desugar(ir))
255*99e0aae7SDavid Rees
256*99e0aae7SDavid Rees  def test_next_in_size(self):
257*99e0aae7SDavid Rees    ir = self._make_ir("struct Foo:\n"
258*99e0aae7SDavid Rees                       "  0 [+2]      UInt:8[]  a\n"
259*99e0aae7SDavid Rees                       "  1 [+$next]  UInt      b\n")
260*99e0aae7SDavid Rees    struct = ir.module[0].type[0].structure
261*99e0aae7SDavid Rees    self.assertEqual([[
262*99e0aae7SDavid Rees        error.error("m.emb", struct.field[1].location.size.source_location,
263*99e0aae7SDavid Rees                    "`$next` may only be used in the start expression of a " +
264*99e0aae7SDavid Rees                    "physical field."),
265*99e0aae7SDavid Rees    ]], synthetics.desugar(ir))
266*99e0aae7SDavid Rees
267*99e0aae7SDavid Rees
268*99e0aae7SDavid Reesif __name__ == "__main__":
269*99e0aae7SDavid Rees  unittest.main()
270