blob: 9920db487b45d61209ec092a8ac222b45b459002 [file] [log] [blame]
Ben Olmsteadc0d77842019-07-31 17:34:05 -07001# 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"""Module which adds and verifies attributes in Emboss IR.
16
17The main entry point is normalize_and_verify(), which adds attributes and/or
18verifies attributes which may have been manually entered.
19"""
20
Dmitri Prime5b381262023-05-01 23:55:07 -070021import re
22
reventlov6731fc42019-10-03 15:23:13 -070023from compiler.front_end import attributes
24from compiler.front_end import type_check
Dmitri Prime5b381262023-05-01 23:55:07 -070025from compiler.util import attribute_util
reventlov6731fc42019-10-03 15:23:13 -070026from compiler.util import error
Eric Rahm12c5e842024-03-22 09:37:24 -070027from compiler.util import ir_data
Eric Rahm3daec5c2024-04-15 12:30:02 -070028from compiler.util import ir_data_utils
reventlov6731fc42019-10-03 15:23:13 -070029from compiler.util import ir_util
30from compiler.util import traverse_ir
Ben Olmsteadc0d77842019-07-31 17:34:05 -070031
Ben Olmsteadc0d77842019-07-31 17:34:05 -070032
reventlovc50913d2022-04-18 15:28:36 -070033# Default value for maximum_bits on an `enum`.
34_DEFAULT_ENUM_MAXIMUM_BITS = 64
35
Dmitri Prime5b381262023-05-01 23:55:07 -070036# Default value for expected_back_ends -- mostly for legacy
37_DEFAULT_BACK_ENDS = "cpp"
reventlovc50913d2022-04-18 15:28:36 -070038
Ben Olmsteadc0d77842019-07-31 17:34:05 -070039# Attribute type checkers
Dmitri Prime5b381262023-05-01 23:55:07 -070040_VALID_BYTE_ORDER = attribute_util.string_from_list(
Dmitri Prime495d3f22024-09-06 16:56:59 -070041 {"BigEndian", "LittleEndian", "Null"}
42)
Dmitri Prime5b381262023-05-01 23:55:07 -070043_VALID_TEXT_OUTPUT = attribute_util.string_from_list({"Emit", "Skip"})
44
45
46def _valid_back_ends(attr, module_source_file):
Dmitri Prime800bd4a2024-09-20 10:19:16 -070047 """Checks that `attr` holds a valid list of back end specifiers."""
Ben Olmstead02a08ab2024-09-09 22:12:54 +000048 if not re.fullmatch(
49 r"(?:\s*[a-z][a-z0-9_]*\s*(?:,\s*[a-z][a-z0-9_]*\s*)*,?)?\s*",
Dmitri Prime495d3f22024-09-06 16:56:59 -070050 attr.value.string_constant.text,
51 ):
52 return [
53 [
54 error.error(
55 module_source_file,
56 attr.value.source_location,
57 "Attribute '{name}' must be a comma-delimited list of back end "
58 'specifiers (like "cpp, proto")), not "{value}".'.format(
59 name=attr.name.text, value=attr.value.string_constant.text
60 ),
61 )
62 ]
63 ]
64 return []
Ben Olmsteadc0d77842019-07-31 17:34:05 -070065
66
Ben Olmsteadc0d77842019-07-31 17:34:05 -070067# Attributes must be the same type no matter where they occur.
68_ATTRIBUTE_TYPES = {
Dmitri Prime5b381262023-05-01 23:55:07 -070069 attributes.ADDRESSABLE_UNIT_SIZE: attribute_util.INTEGER_CONSTANT,
70 attributes.BYTE_ORDER: _VALID_BYTE_ORDER,
71 attributes.ENUM_MAXIMUM_BITS: attribute_util.INTEGER_CONSTANT,
72 attributes.FIXED_SIZE: attribute_util.INTEGER_CONSTANT,
73 attributes.IS_INTEGER: attribute_util.BOOLEAN_CONSTANT,
74 attributes.IS_SIGNED: attribute_util.BOOLEAN_CONSTANT,
75 attributes.REQUIRES: attribute_util.BOOLEAN,
76 attributes.STATIC_REQUIREMENTS: attribute_util.BOOLEAN,
77 attributes.TEXT_OUTPUT: _VALID_TEXT_OUTPUT,
78 attributes.BACK_ENDS: _valid_back_ends,
Ben Olmsteadc0d77842019-07-31 17:34:05 -070079}
80
81_MODULE_ATTRIBUTES = {
Dmitri Prime5b381262023-05-01 23:55:07 -070082 (attributes.BYTE_ORDER, True),
83 (attributes.BACK_ENDS, False),
Ben Olmsteadc0d77842019-07-31 17:34:05 -070084}
85_BITS_ATTRIBUTES = {
Dmitri Prime5b381262023-05-01 23:55:07 -070086 (attributes.FIXED_SIZE, False),
87 (attributes.REQUIRES, False),
Ben Olmsteadc0d77842019-07-31 17:34:05 -070088}
89_STRUCT_ATTRIBUTES = {
Dmitri Prime5b381262023-05-01 23:55:07 -070090 (attributes.FIXED_SIZE, False),
91 (attributes.BYTE_ORDER, True),
92 (attributes.REQUIRES, False),
Ben Olmsteadc0d77842019-07-31 17:34:05 -070093}
94_ENUM_ATTRIBUTES = {
Dmitri Prime5b381262023-05-01 23:55:07 -070095 (attributes.ENUM_MAXIMUM_BITS, False),
96 (attributes.IS_SIGNED, False),
Ben Olmsteadc0d77842019-07-31 17:34:05 -070097}
98_EXTERNAL_ATTRIBUTES = {
Dmitri Prime5b381262023-05-01 23:55:07 -070099 (attributes.ADDRESSABLE_UNIT_SIZE, False),
100 (attributes.FIXED_SIZE, False),
101 (attributes.IS_INTEGER, False),
102 (attributes.STATIC_REQUIREMENTS, False),
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700103}
104_STRUCT_PHYSICAL_FIELD_ATTRIBUTES = {
Dmitri Prime5b381262023-05-01 23:55:07 -0700105 (attributes.BYTE_ORDER, False),
106 (attributes.REQUIRES, False),
107 (attributes.TEXT_OUTPUT, False),
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700108}
109_STRUCT_VIRTUAL_FIELD_ATTRIBUTES = {
Dmitri Prime5b381262023-05-01 23:55:07 -0700110 (attributes.REQUIRES, False),
111 (attributes.TEXT_OUTPUT, False),
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700112}
113
114
115def _construct_integer_attribute(name, value, source_location):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700116 """Constructs an integer Attribute with the given name and value."""
117 attr_value = ir_data.AttributeValue(
118 expression=ir_data.Expression(
119 constant=ir_data.NumericConstant(
120 value=str(value), source_location=source_location
121 ),
122 type=ir_data.ExpressionType(
123 integer=ir_data.IntegerType(
124 modular_value=str(value),
125 modulus="infinity",
126 minimum_value=str(value),
127 maximum_value=str(value),
128 )
129 ),
130 source_location=source_location,
131 ),
132 source_location=source_location,
133 )
134 return ir_data.Attribute(
135 name=ir_data.Word(text=name, source_location=source_location),
136 value=attr_value,
137 source_location=source_location,
138 )
reventlovc50913d2022-04-18 15:28:36 -0700139
140
141def _construct_boolean_attribute(name, value, source_location):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700142 """Constructs a boolean Attribute with the given name and value."""
143 attr_value = ir_data.AttributeValue(
144 expression=ir_data.Expression(
145 boolean_constant=ir_data.BooleanConstant(
146 value=value, source_location=source_location
147 ),
148 type=ir_data.ExpressionType(boolean=ir_data.BooleanType(value=value)),
149 source_location=source_location,
150 ),
151 source_location=source_location,
152 )
153 return ir_data.Attribute(
154 name=ir_data.Word(text=name, source_location=source_location),
155 value=attr_value,
156 source_location=source_location,
157 )
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700158
159
160def _construct_string_attribute(name, value, source_location):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700161 """Constructs a string Attribute with the given name and value."""
162 attr_value = ir_data.AttributeValue(
163 string_constant=ir_data.String(text=value, source_location=source_location),
164 source_location=source_location,
165 )
166 return ir_data.Attribute(
167 name=ir_data.Word(text=name, source_location=source_location),
168 value=attr_value,
169 source_location=source_location,
170 )
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700171
172
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700173def _fixed_size_of_struct_or_bits(struct, unit_size):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700174 """Returns size of struct in bits or None, if struct is not fixed size."""
175 size = 0
176 for field in struct.field:
177 if not field.HasField("location"):
178 # Virtual fields do not contribute to the physical size of the struct.
179 continue
180 field_start = ir_util.constant_value(field.location.start)
181 field_size = ir_util.constant_value(field.location.size)
182 if field_start is None or field_size is None:
183 # Technically, start + size could be constant even if start and size are
184 # not; e.g. if start == x and size == 10 - x, but we don't handle that
185 # here.
186 return None
187 # TODO(bolms): knows_own_size
188 # TODO(bolms): compute min/max sizes for variable-sized arrays.
189 field_end = field_start + field_size
190 if field_end >= size:
191 size = field_end
192 return size * unit_size
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700193
194
Dmitri Prime495d3f22024-09-06 16:56:59 -0700195def _verify_size_attributes_on_structure(
196 struct, type_definition, source_file_name, errors
197):
198 """Verifies size attributes on a struct or bits."""
199 fixed_size = _fixed_size_of_struct_or_bits(struct, type_definition.addressable_unit)
200 fixed_size_attr = ir_util.get_attribute(
201 type_definition.attribute, attributes.FIXED_SIZE
202 )
203 if not fixed_size_attr:
204 return
205 if fixed_size is None:
206 errors.append(
207 [
208 error.error(
209 source_file_name,
210 fixed_size_attr.source_location,
211 "Struct is marked as fixed size, but contains variable-location "
212 "fields.",
213 )
214 ]
215 )
216 elif ir_util.constant_value(fixed_size_attr.expression) != fixed_size:
217 errors.append(
218 [
219 error.error(
220 source_file_name,
221 fixed_size_attr.source_location,
222 "Struct is {} bits, but is marked as {} bits.".format(
223 fixed_size, ir_util.constant_value(fixed_size_attr.expression)
224 ),
225 )
226 ]
227 )
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700228
229
230# TODO(bolms): remove [fixed_size]; it is superseded by $size_in_{bits,bytes}
231def _add_missing_size_attributes_on_structure(struct, type_definition):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700232 """Adds missing size attributes on a struct."""
233 fixed_size = _fixed_size_of_struct_or_bits(struct, type_definition.addressable_unit)
234 if fixed_size is None:
235 return
236 fixed_size_attr = ir_util.get_attribute(
237 type_definition.attribute, attributes.FIXED_SIZE
238 )
239 if not fixed_size_attr:
240 # TODO(bolms): Use the offset and length of the last field as the
241 # source_location of the fixed_size attribute?
242 type_definition.attribute.extend(
243 [
244 _construct_integer_attribute(
245 attributes.FIXED_SIZE, fixed_size, type_definition.source_location
246 )
247 ]
248 )
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700249
250
251def _field_needs_byte_order(field, type_definition, ir):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700252 """Returns true if the given field needs a byte_order attribute."""
253 if ir_util.field_is_virtual(field):
254 # Virtual fields have no physical type, and thus do not need a byte order.
255 return False
256 field_type = ir_util.find_object(
257 ir_util.get_base_type(field.type).atomic_type.reference.canonical_name, ir
258 )
259 assert field_type is not None
260 assert field_type.addressable_unit != ir_data.AddressableUnit.NONE
261 return field_type.addressable_unit != type_definition.addressable_unit
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700262
263
264def _field_may_have_null_byte_order(field, type_definition, ir):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700265 """Returns true if "Null" is a valid byte order for the given field."""
266 # If the field is one unit in length, then byte order does not matter.
267 if (
268 ir_util.is_constant(field.location.size)
269 and ir_util.constant_value(field.location.size) == 1
270 ):
271 return True
272 unit = type_definition.addressable_unit
273 # Otherwise, if the field's type is either a one-unit-sized type or an array
274 # of a one-unit-sized type, then byte order does not matter.
275 if (
276 ir_util.fixed_size_of_type_in_bits(ir_util.get_base_type(field.type), ir)
277 == unit
278 ):
279 return True
280 # In all other cases, byte order does matter.
281 return False
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700282
283
Dmitri Prime495d3f22024-09-06 16:56:59 -0700284def _add_missing_byte_order_attribute_on_field(field, type_definition, ir, defaults):
285 """Adds missing byte_order attributes to fields that need them."""
286 if _field_needs_byte_order(field, type_definition, ir):
287 byte_order_attr = ir_util.get_attribute(field.attribute, attributes.BYTE_ORDER)
288 if byte_order_attr is None:
289 if attributes.BYTE_ORDER in defaults:
290 field.attribute.extend([defaults[attributes.BYTE_ORDER]])
291 elif _field_may_have_null_byte_order(field, type_definition, ir):
292 field.attribute.extend(
293 [
294 _construct_string_attribute(
295 attributes.BYTE_ORDER, "Null", field.source_location
296 )
297 ]
298 )
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700299
300
Dmitri Prime5b381262023-05-01 23:55:07 -0700301def _add_missing_back_ends_to_module(module):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700302 """Sets the expected_back_ends attribute for a module, if not already set."""
303 back_ends_attr = ir_util.get_attribute(module.attribute, attributes.BACK_ENDS)
304 if back_ends_attr is None:
305 module.attribute.extend(
306 [
307 _construct_string_attribute(
308 attributes.BACK_ENDS, _DEFAULT_BACK_ENDS, module.source_location
309 )
310 ]
311 )
Dmitri Prime5b381262023-05-01 23:55:07 -0700312
313
314def _gather_expected_back_ends(module):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700315 """Captures the expected_back_ends attribute for `module`."""
316 back_ends_attr = ir_util.get_attribute(module.attribute, attributes.BACK_ENDS)
317 back_ends_str = back_ends_attr.string_constant.text
318 return {"expected_back_ends": {x.strip() for x in back_ends_str.split(",")} | {""}}
Dmitri Prime5b381262023-05-01 23:55:07 -0700319
320
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700321def _add_addressable_unit_to_external(external, type_definition):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700322 """Sets the addressable_unit field for an external TypeDefinition."""
323 # Strictly speaking, addressable_unit isn't an "attribute," but it's close
324 # enough that it makes sense to handle it with attributes.
325 del external # Unused.
326 size = ir_util.get_integer_attribute(
327 type_definition.attribute, attributes.ADDRESSABLE_UNIT_SIZE
328 )
329 if size == 1:
330 type_definition.addressable_unit = ir_data.AddressableUnit.BIT
331 elif size == 8:
332 type_definition.addressable_unit = ir_data.AddressableUnit.BYTE
333 # If the addressable_unit_size is not in (1, 8), it will be caught by
334 # _verify_addressable_unit_attribute_on_external, below.
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700335
336
reventlovc50913d2022-04-18 15:28:36 -0700337def _add_missing_width_and_sign_attributes_on_enum(enum, type_definition):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700338 """Sets the maximum_bits and is_signed attributes for an enum, if needed."""
339 max_bits_attr = ir_util.get_integer_attribute(
340 type_definition.attribute, attributes.ENUM_MAXIMUM_BITS
341 )
342 if max_bits_attr is None:
343 type_definition.attribute.extend(
344 [
345 _construct_integer_attribute(
346 attributes.ENUM_MAXIMUM_BITS,
347 _DEFAULT_ENUM_MAXIMUM_BITS,
348 type_definition.source_location,
349 )
350 ]
351 )
352 signed_attr = ir_util.get_boolean_attribute(
353 type_definition.attribute, attributes.IS_SIGNED
354 )
355 if signed_attr is None:
356 for value in enum.value:
357 numeric_value = ir_util.constant_value(value.value)
358 if numeric_value < 0:
359 is_signed = True
360 break
361 else:
362 is_signed = False
363 type_definition.attribute.extend(
364 [
365 _construct_boolean_attribute(
366 attributes.IS_SIGNED, is_signed, type_definition.source_location
367 )
368 ]
369 )
reventlovc50913d2022-04-18 15:28:36 -0700370
371
Dmitri Prime495d3f22024-09-06 16:56:59 -0700372def _verify_byte_order_attribute_on_field(
373 field, type_definition, source_file_name, ir, errors
374):
375 """Verifies the byte_order attribute on the given field."""
376 byte_order_attr = ir_util.get_attribute(field.attribute, attributes.BYTE_ORDER)
377 field_needs_byte_order = _field_needs_byte_order(field, type_definition, ir)
378 if byte_order_attr and not field_needs_byte_order:
379 errors.append(
380 [
381 error.error(
382 source_file_name,
383 byte_order_attr.source_location,
384 "Attribute 'byte_order' not allowed on field which is not byte order "
385 "dependent.",
386 )
387 ]
388 )
389 if not byte_order_attr and field_needs_byte_order:
390 errors.append(
391 [
392 error.error(
393 source_file_name,
394 field.source_location,
395 "Attribute 'byte_order' required on field which is byte order "
396 "dependent.",
397 )
398 ]
399 )
400 if (
401 byte_order_attr
402 and byte_order_attr.string_constant.text == "Null"
403 and not _field_may_have_null_byte_order(field, type_definition, ir)
404 ):
405 errors.append(
406 [
407 error.error(
408 source_file_name,
409 byte_order_attr.source_location,
410 "Attribute 'byte_order' may only be 'Null' for one-byte fields.",
411 )
412 ]
413 )
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700414
415
416def _verify_requires_attribute_on_field(field, source_file_name, ir, errors):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700417 """Verifies that [requires] is valid on the given field."""
418 requires_attr = ir_util.get_attribute(field.attribute, attributes.REQUIRES)
419 if not requires_attr:
420 return
421 if ir_util.field_is_virtual(field):
422 field_expression_type = field.read_transform.type
423 else:
424 if not field.type.HasField("atomic_type"):
425 errors.append(
426 [
427 error.error(
428 source_file_name,
429 requires_attr.source_location,
430 "Attribute 'requires' is only allowed on integer, "
431 "enumeration, or boolean fields, not arrays.",
432 ),
433 error.note(
434 source_file_name, field.type.source_location, "Field type."
435 ),
436 ]
437 )
438 return
439 field_type = ir_util.find_object(field.type.atomic_type.reference, ir)
440 assert field_type, "Field type should be non-None after name resolution."
441 field_expression_type = type_check.unbounded_expression_type_for_physical_type(
442 field_type
443 )
Dmitri Primebd276c42024-10-11 12:59:21 -0700444 if field_expression_type.which_type not in (
Dmitri Prime495d3f22024-09-06 16:56:59 -0700445 "integer",
446 "enumeration",
447 "boolean",
448 ):
449 errors.append(
450 [
451 error.error(
452 source_file_name,
453 requires_attr.source_location,
454 "Attribute 'requires' is only allowed on integer, enumeration, or "
455 "boolean fields.",
456 )
457 ]
458 )
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700459
460
Dmitri Prime495d3f22024-09-06 16:56:59 -0700461def _verify_addressable_unit_attribute_on_external(
462 external, type_definition, source_file_name, errors
463):
464 """Verifies the addressable_unit_size attribute on an external."""
465 del external # Unused.
466 addressable_unit_size_attr = ir_util.get_integer_attribute(
467 type_definition.attribute, attributes.ADDRESSABLE_UNIT_SIZE
468 )
469 if addressable_unit_size_attr is None:
470 errors.append(
471 [
472 error.error(
473 source_file_name,
474 type_definition.source_location,
475 "Expected '{}' attribute for external type.".format(
476 attributes.ADDRESSABLE_UNIT_SIZE
477 ),
478 )
479 ]
480 )
481 elif addressable_unit_size_attr not in (1, 8):
482 errors.append(
483 [
484 error.error(
485 source_file_name,
486 type_definition.source_location,
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700487 "Only values '1' (bit) and '8' (byte) are allowed for the "
Dmitri Prime495d3f22024-09-06 16:56:59 -0700488 "'{}' attribute".format(attributes.ADDRESSABLE_UNIT_SIZE),
489 )
490 ]
491 )
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700492
493
Dmitri Prime495d3f22024-09-06 16:56:59 -0700494def _verify_width_attribute_on_enum(enum, type_definition, source_file_name, errors):
495 """Verifies the maximum_bits attribute for an enum TypeDefinition."""
Ben Olmstead1a8f8522024-09-09 20:13:26 +0000496 del enum # Unused.
Dmitri Prime495d3f22024-09-06 16:56:59 -0700497 max_bits_value = ir_util.get_integer_attribute(
498 type_definition.attribute, attributes.ENUM_MAXIMUM_BITS
499 )
500 # The attribute should already have been defaulted, if not originally present.
501 assert max_bits_value is not None, "maximum_bits not set"
502 if max_bits_value > 64 or max_bits_value < 1:
503 max_bits_attr = ir_util.get_attribute(
504 type_definition.attribute, attributes.ENUM_MAXIMUM_BITS
505 )
506 errors.append(
507 [
508 error.error(
509 source_file_name,
510 max_bits_attr.source_location,
511 "'maximum_bits' on an 'enum' must be between 1 and 64.",
512 )
513 ]
514 )
reventlovc50913d2022-04-18 15:28:36 -0700515
516
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700517def _add_missing_attributes_on_ir(ir):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700518 """Adds missing attributes in a complete IR."""
519 traverse_ir.fast_traverse_ir_top_down(
520 ir, [ir_data.Module], _add_missing_back_ends_to_module
521 )
522 traverse_ir.fast_traverse_ir_top_down(
523 ir, [ir_data.External], _add_addressable_unit_to_external
524 )
525 traverse_ir.fast_traverse_ir_top_down(
526 ir, [ir_data.Enum], _add_missing_width_and_sign_attributes_on_enum
527 )
528 traverse_ir.fast_traverse_ir_top_down(
529 ir,
530 [ir_data.Structure],
531 _add_missing_size_attributes_on_structure,
532 incidental_actions={
533 ir_data.Module: attribute_util.gather_default_attributes,
534 ir_data.TypeDefinition: attribute_util.gather_default_attributes,
535 ir_data.Field: attribute_util.gather_default_attributes,
536 },
537 parameters={"defaults": {}},
538 )
539 traverse_ir.fast_traverse_ir_top_down(
540 ir,
541 [ir_data.Field],
542 _add_missing_byte_order_attribute_on_field,
543 incidental_actions={
544 ir_data.Module: attribute_util.gather_default_attributes,
545 ir_data.TypeDefinition: attribute_util.gather_default_attributes,
546 ir_data.Field: attribute_util.gather_default_attributes,
547 },
548 parameters={"defaults": {}},
549 )
550 return []
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700551
552
Dmitri Prime495d3f22024-09-06 16:56:59 -0700553def _verify_field_attributes(field, type_definition, source_file_name, ir, errors):
554 _verify_byte_order_attribute_on_field(
555 field, type_definition, source_file_name, ir, errors
556 )
557 _verify_requires_attribute_on_field(field, source_file_name, ir, errors)
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700558
559
Dmitri Prime495d3f22024-09-06 16:56:59 -0700560def _verify_back_end_attributes(
Ben Olmstead1a8f8522024-09-09 20:13:26 +0000561 attribute, expected_back_ends, source_file_name, errors
Dmitri Prime495d3f22024-09-06 16:56:59 -0700562):
563 back_end_text = ir_data_utils.reader(attribute).back_end.text
564 if back_end_text not in expected_back_ends:
565 expected_back_ends_for_error = expected_back_ends - {""}
566 errors.append(
567 [
568 error.error(
569 source_file_name,
570 attribute.back_end.source_location,
571 "Back end specifier '{back_end}' does not match any expected back end "
572 "specifier for this file: '{expected_back_ends}'. Add or update the "
573 "'[expected_back_ends: \"{new_expected_back_ends}\"]' attribute at the "
574 "file level if this back end specifier is intentional.".format(
575 back_end=attribute.back_end.text,
576 expected_back_ends="', '".join(
577 sorted(expected_back_ends_for_error)
578 ),
579 new_expected_back_ends=", ".join(
580 sorted(expected_back_ends_for_error | {back_end_text})
581 ),
582 ),
583 )
584 ]
585 )
Dmitri Prime5b381262023-05-01 23:55:07 -0700586
587
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700588def _verify_attributes_on_ir(ir):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700589 """Verifies attributes in a complete IR."""
590 errors = []
591 traverse_ir.fast_traverse_ir_top_down(
592 ir,
593 [ir_data.Attribute],
594 _verify_back_end_attributes,
595 incidental_actions={
596 ir_data.Module: _gather_expected_back_ends,
597 },
598 parameters={"errors": errors},
599 )
600 traverse_ir.fast_traverse_ir_top_down(
601 ir,
602 [ir_data.Structure],
603 _verify_size_attributes_on_structure,
604 parameters={"errors": errors},
605 )
606 traverse_ir.fast_traverse_ir_top_down(
607 ir,
608 [ir_data.Enum],
609 _verify_width_attribute_on_enum,
610 parameters={"errors": errors},
611 )
612 traverse_ir.fast_traverse_ir_top_down(
613 ir,
614 [ir_data.External],
615 _verify_addressable_unit_attribute_on_external,
616 parameters={"errors": errors},
617 )
618 traverse_ir.fast_traverse_ir_top_down(
619 ir, [ir_data.Field], _verify_field_attributes, parameters={"errors": errors}
620 )
621 return errors
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700622
623
624def normalize_and_verify(ir):
Dmitri Prime495d3f22024-09-06 16:56:59 -0700625 """Performs various normalizations and verifications on ir.
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700626
Dmitri Prime495d3f22024-09-06 16:56:59 -0700627 Checks for duplicate attributes.
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700628
Dmitri Prime495d3f22024-09-06 16:56:59 -0700629 Adds fixed_size_in_bits and addressable_unit_size attributes to types when
630 they are missing, and checks their correctness when they are not missing.
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700631
Dmitri Prime495d3f22024-09-06 16:56:59 -0700632 Arguments:
633 ir: The IR object to normalize.
Ben Olmsteadc0d77842019-07-31 17:34:05 -0700634
Dmitri Prime495d3f22024-09-06 16:56:59 -0700635 Returns:
636 A list of validation errors, or an empty list if no errors were encountered.
637 """
638 errors = attribute_util.check_attributes_in_ir(
639 ir,
640 types=_ATTRIBUTE_TYPES,
641 module_attributes=_MODULE_ATTRIBUTES,
642 struct_attributes=_STRUCT_ATTRIBUTES,
643 bits_attributes=_BITS_ATTRIBUTES,
644 enum_attributes=_ENUM_ATTRIBUTES,
645 external_attributes=_EXTERNAL_ATTRIBUTES,
646 structure_virtual_field_attributes=_STRUCT_VIRTUAL_FIELD_ATTRIBUTES,
647 structure_physical_field_attributes=_STRUCT_PHYSICAL_FIELD_ATTRIBUTES,
648 )
649 if errors:
650 return errors
651 _add_missing_attributes_on_ir(ir)
652 return _verify_attributes_on_ir(ir)