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"""Module which adds and verifies attributes in Emboss IR. 16*99e0aae7SDavid Rees 17*99e0aae7SDavid ReesThe main entry point is normalize_and_verify(), which adds attributes and/or 18*99e0aae7SDavid Reesverifies attributes which may have been manually entered. 19*99e0aae7SDavid Rees""" 20*99e0aae7SDavid Rees 21*99e0aae7SDavid Reesimport re 22*99e0aae7SDavid Rees 23*99e0aae7SDavid Reesfrom compiler.front_end import attributes 24*99e0aae7SDavid Reesfrom compiler.front_end import type_check 25*99e0aae7SDavid Reesfrom compiler.util import attribute_util 26*99e0aae7SDavid Reesfrom compiler.util import error 27*99e0aae7SDavid Reesfrom compiler.util import ir_data 28*99e0aae7SDavid Reesfrom compiler.util import ir_data_utils 29*99e0aae7SDavid Reesfrom compiler.util import ir_util 30*99e0aae7SDavid Reesfrom compiler.util import traverse_ir 31*99e0aae7SDavid Rees 32*99e0aae7SDavid Rees 33*99e0aae7SDavid Rees# Default value for maximum_bits on an `enum`. 34*99e0aae7SDavid Rees_DEFAULT_ENUM_MAXIMUM_BITS = 64 35*99e0aae7SDavid Rees 36*99e0aae7SDavid Rees# Default value for expected_back_ends -- mostly for legacy 37*99e0aae7SDavid Rees_DEFAULT_BACK_ENDS = "cpp" 38*99e0aae7SDavid Rees 39*99e0aae7SDavid Rees# Attribute type checkers 40*99e0aae7SDavid Rees_VALID_BYTE_ORDER = attribute_util.string_from_list( 41*99e0aae7SDavid Rees {"BigEndian", "LittleEndian", "Null"}) 42*99e0aae7SDavid Rees_VALID_TEXT_OUTPUT = attribute_util.string_from_list({"Emit", "Skip"}) 43*99e0aae7SDavid Rees 44*99e0aae7SDavid Rees 45*99e0aae7SDavid Reesdef _valid_back_ends(attr, module_source_file): 46*99e0aae7SDavid Rees if not re.match( 47*99e0aae7SDavid Rees r"^(?:\s*[a-z][a-z0-9_]*\s*(?:,\s*[a-z][a-z0-9_]*\s*)*,?)?\s*$", 48*99e0aae7SDavid Rees attr.value.string_constant.text): 49*99e0aae7SDavid Rees return [[error.error( 50*99e0aae7SDavid Rees module_source_file, 51*99e0aae7SDavid Rees attr.value.source_location, 52*99e0aae7SDavid Rees "Attribute '{name}' must be a comma-delimited list of back end " 53*99e0aae7SDavid Rees "specifiers (like \"cpp, proto\")), not \"{value}\".".format( 54*99e0aae7SDavid Rees name=attr.name.text, 55*99e0aae7SDavid Rees value=attr.value.string_constant.text))]] 56*99e0aae7SDavid Rees return [] 57*99e0aae7SDavid Rees 58*99e0aae7SDavid Rees 59*99e0aae7SDavid Rees# Attributes must be the same type no matter where they occur. 60*99e0aae7SDavid Rees_ATTRIBUTE_TYPES = { 61*99e0aae7SDavid Rees attributes.ADDRESSABLE_UNIT_SIZE: attribute_util.INTEGER_CONSTANT, 62*99e0aae7SDavid Rees attributes.BYTE_ORDER: _VALID_BYTE_ORDER, 63*99e0aae7SDavid Rees attributes.ENUM_MAXIMUM_BITS: attribute_util.INTEGER_CONSTANT, 64*99e0aae7SDavid Rees attributes.FIXED_SIZE: attribute_util.INTEGER_CONSTANT, 65*99e0aae7SDavid Rees attributes.IS_INTEGER: attribute_util.BOOLEAN_CONSTANT, 66*99e0aae7SDavid Rees attributes.IS_SIGNED: attribute_util.BOOLEAN_CONSTANT, 67*99e0aae7SDavid Rees attributes.REQUIRES: attribute_util.BOOLEAN, 68*99e0aae7SDavid Rees attributes.STATIC_REQUIREMENTS: attribute_util.BOOLEAN, 69*99e0aae7SDavid Rees attributes.TEXT_OUTPUT: _VALID_TEXT_OUTPUT, 70*99e0aae7SDavid Rees attributes.BACK_ENDS: _valid_back_ends, 71*99e0aae7SDavid Rees} 72*99e0aae7SDavid Rees 73*99e0aae7SDavid Rees_MODULE_ATTRIBUTES = { 74*99e0aae7SDavid Rees (attributes.BYTE_ORDER, True), 75*99e0aae7SDavid Rees (attributes.BACK_ENDS, False), 76*99e0aae7SDavid Rees} 77*99e0aae7SDavid Rees_BITS_ATTRIBUTES = { 78*99e0aae7SDavid Rees (attributes.FIXED_SIZE, False), 79*99e0aae7SDavid Rees (attributes.REQUIRES, False), 80*99e0aae7SDavid Rees} 81*99e0aae7SDavid Rees_STRUCT_ATTRIBUTES = { 82*99e0aae7SDavid Rees (attributes.FIXED_SIZE, False), 83*99e0aae7SDavid Rees (attributes.BYTE_ORDER, True), 84*99e0aae7SDavid Rees (attributes.REQUIRES, False), 85*99e0aae7SDavid Rees} 86*99e0aae7SDavid Rees_ENUM_ATTRIBUTES = { 87*99e0aae7SDavid Rees (attributes.ENUM_MAXIMUM_BITS, False), 88*99e0aae7SDavid Rees (attributes.IS_SIGNED, False), 89*99e0aae7SDavid Rees} 90*99e0aae7SDavid Rees_EXTERNAL_ATTRIBUTES = { 91*99e0aae7SDavid Rees (attributes.ADDRESSABLE_UNIT_SIZE, False), 92*99e0aae7SDavid Rees (attributes.FIXED_SIZE, False), 93*99e0aae7SDavid Rees (attributes.IS_INTEGER, False), 94*99e0aae7SDavid Rees (attributes.STATIC_REQUIREMENTS, False), 95*99e0aae7SDavid Rees} 96*99e0aae7SDavid Rees_STRUCT_PHYSICAL_FIELD_ATTRIBUTES = { 97*99e0aae7SDavid Rees (attributes.BYTE_ORDER, False), 98*99e0aae7SDavid Rees (attributes.REQUIRES, False), 99*99e0aae7SDavid Rees (attributes.TEXT_OUTPUT, False), 100*99e0aae7SDavid Rees} 101*99e0aae7SDavid Rees_STRUCT_VIRTUAL_FIELD_ATTRIBUTES = { 102*99e0aae7SDavid Rees (attributes.REQUIRES, False), 103*99e0aae7SDavid Rees (attributes.TEXT_OUTPUT, False), 104*99e0aae7SDavid Rees} 105*99e0aae7SDavid Rees 106*99e0aae7SDavid Rees 107*99e0aae7SDavid Reesdef _construct_integer_attribute(name, value, source_location): 108*99e0aae7SDavid Rees """Constructs an integer Attribute with the given name and value.""" 109*99e0aae7SDavid Rees attr_value = ir_data.AttributeValue( 110*99e0aae7SDavid Rees expression=ir_data.Expression( 111*99e0aae7SDavid Rees constant=ir_data.NumericConstant(value=str(value), 112*99e0aae7SDavid Rees source_location=source_location), 113*99e0aae7SDavid Rees type=ir_data.ExpressionType( 114*99e0aae7SDavid Rees integer=ir_data.IntegerType(modular_value=str(value), 115*99e0aae7SDavid Rees modulus="infinity", 116*99e0aae7SDavid Rees minimum_value=str(value), 117*99e0aae7SDavid Rees maximum_value=str(value))), 118*99e0aae7SDavid Rees source_location=source_location), 119*99e0aae7SDavid Rees source_location=source_location) 120*99e0aae7SDavid Rees return ir_data.Attribute(name=ir_data.Word(text=name, 121*99e0aae7SDavid Rees source_location=source_location), 122*99e0aae7SDavid Rees value=attr_value, 123*99e0aae7SDavid Rees source_location=source_location) 124*99e0aae7SDavid Rees 125*99e0aae7SDavid Rees 126*99e0aae7SDavid Reesdef _construct_boolean_attribute(name, value, source_location): 127*99e0aae7SDavid Rees """Constructs a boolean Attribute with the given name and value.""" 128*99e0aae7SDavid Rees attr_value = ir_data.AttributeValue( 129*99e0aae7SDavid Rees expression=ir_data.Expression( 130*99e0aae7SDavid Rees boolean_constant=ir_data.BooleanConstant( 131*99e0aae7SDavid Rees value=value, source_location=source_location), 132*99e0aae7SDavid Rees type=ir_data.ExpressionType(boolean=ir_data.BooleanType(value=value)), 133*99e0aae7SDavid Rees source_location=source_location), 134*99e0aae7SDavid Rees source_location=source_location) 135*99e0aae7SDavid Rees return ir_data.Attribute(name=ir_data.Word(text=name, 136*99e0aae7SDavid Rees source_location=source_location), 137*99e0aae7SDavid Rees value=attr_value, 138*99e0aae7SDavid Rees source_location=source_location) 139*99e0aae7SDavid Rees 140*99e0aae7SDavid Rees 141*99e0aae7SDavid Reesdef _construct_string_attribute(name, value, source_location): 142*99e0aae7SDavid Rees """Constructs a string Attribute with the given name and value.""" 143*99e0aae7SDavid Rees attr_value = ir_data.AttributeValue( 144*99e0aae7SDavid Rees string_constant=ir_data.String(text=value, 145*99e0aae7SDavid Rees source_location=source_location), 146*99e0aae7SDavid Rees source_location=source_location) 147*99e0aae7SDavid Rees return ir_data.Attribute(name=ir_data.Word(text=name, 148*99e0aae7SDavid Rees source_location=source_location), 149*99e0aae7SDavid Rees value=attr_value, 150*99e0aae7SDavid Rees source_location=source_location) 151*99e0aae7SDavid Rees 152*99e0aae7SDavid Rees 153*99e0aae7SDavid Reesdef _fixed_size_of_struct_or_bits(struct, unit_size): 154*99e0aae7SDavid Rees """Returns size of struct in bits or None, if struct is not fixed size.""" 155*99e0aae7SDavid Rees size = 0 156*99e0aae7SDavid Rees for field in struct.field: 157*99e0aae7SDavid Rees if not field.HasField("location"): 158*99e0aae7SDavid Rees # Virtual fields do not contribute to the physical size of the struct. 159*99e0aae7SDavid Rees continue 160*99e0aae7SDavid Rees field_start = ir_util.constant_value(field.location.start) 161*99e0aae7SDavid Rees field_size = ir_util.constant_value(field.location.size) 162*99e0aae7SDavid Rees if field_start is None or field_size is None: 163*99e0aae7SDavid Rees # Technically, start + size could be constant even if start and size are 164*99e0aae7SDavid Rees # not; e.g. if start == x and size == 10 - x, but we don't handle that 165*99e0aae7SDavid Rees # here. 166*99e0aae7SDavid Rees return None 167*99e0aae7SDavid Rees # TODO(bolms): knows_own_size 168*99e0aae7SDavid Rees # TODO(bolms): compute min/max sizes for variable-sized arrays. 169*99e0aae7SDavid Rees field_end = field_start + field_size 170*99e0aae7SDavid Rees if field_end >= size: 171*99e0aae7SDavid Rees size = field_end 172*99e0aae7SDavid Rees return size * unit_size 173*99e0aae7SDavid Rees 174*99e0aae7SDavid Rees 175*99e0aae7SDavid Reesdef _verify_size_attributes_on_structure(struct, type_definition, 176*99e0aae7SDavid Rees source_file_name, errors): 177*99e0aae7SDavid Rees """Verifies size attributes on a struct or bits.""" 178*99e0aae7SDavid Rees fixed_size = _fixed_size_of_struct_or_bits(struct, 179*99e0aae7SDavid Rees type_definition.addressable_unit) 180*99e0aae7SDavid Rees fixed_size_attr = ir_util.get_attribute(type_definition.attribute, 181*99e0aae7SDavid Rees attributes.FIXED_SIZE) 182*99e0aae7SDavid Rees if not fixed_size_attr: 183*99e0aae7SDavid Rees return 184*99e0aae7SDavid Rees if fixed_size is None: 185*99e0aae7SDavid Rees errors.append([error.error( 186*99e0aae7SDavid Rees source_file_name, fixed_size_attr.source_location, 187*99e0aae7SDavid Rees "Struct is marked as fixed size, but contains variable-location " 188*99e0aae7SDavid Rees "fields.")]) 189*99e0aae7SDavid Rees elif ir_util.constant_value(fixed_size_attr.expression) != fixed_size: 190*99e0aae7SDavid Rees errors.append([error.error( 191*99e0aae7SDavid Rees source_file_name, fixed_size_attr.source_location, 192*99e0aae7SDavid Rees "Struct is {} bits, but is marked as {} bits.".format( 193*99e0aae7SDavid Rees fixed_size, ir_util.constant_value(fixed_size_attr.expression)))]) 194*99e0aae7SDavid Rees 195*99e0aae7SDavid Rees 196*99e0aae7SDavid Rees# TODO(bolms): remove [fixed_size]; it is superseded by $size_in_{bits,bytes} 197*99e0aae7SDavid Reesdef _add_missing_size_attributes_on_structure(struct, type_definition): 198*99e0aae7SDavid Rees """Adds missing size attributes on a struct.""" 199*99e0aae7SDavid Rees fixed_size = _fixed_size_of_struct_or_bits(struct, 200*99e0aae7SDavid Rees type_definition.addressable_unit) 201*99e0aae7SDavid Rees if fixed_size is None: 202*99e0aae7SDavid Rees return 203*99e0aae7SDavid Rees fixed_size_attr = ir_util.get_attribute(type_definition.attribute, 204*99e0aae7SDavid Rees attributes.FIXED_SIZE) 205*99e0aae7SDavid Rees if not fixed_size_attr: 206*99e0aae7SDavid Rees # TODO(bolms): Use the offset and length of the last field as the 207*99e0aae7SDavid Rees # source_location of the fixed_size attribute? 208*99e0aae7SDavid Rees type_definition.attribute.extend([ 209*99e0aae7SDavid Rees _construct_integer_attribute(attributes.FIXED_SIZE, fixed_size, 210*99e0aae7SDavid Rees type_definition.source_location)]) 211*99e0aae7SDavid Rees 212*99e0aae7SDavid Rees 213*99e0aae7SDavid Reesdef _field_needs_byte_order(field, type_definition, ir): 214*99e0aae7SDavid Rees """Returns true if the given field needs a byte_order attribute.""" 215*99e0aae7SDavid Rees if ir_util.field_is_virtual(field): 216*99e0aae7SDavid Rees # Virtual fields have no physical type, and thus do not need a byte order. 217*99e0aae7SDavid Rees return False 218*99e0aae7SDavid Rees field_type = ir_util.find_object( 219*99e0aae7SDavid Rees ir_util.get_base_type(field.type).atomic_type.reference.canonical_name, 220*99e0aae7SDavid Rees ir) 221*99e0aae7SDavid Rees assert field_type is not None 222*99e0aae7SDavid Rees assert field_type.addressable_unit != ir_data.AddressableUnit.NONE 223*99e0aae7SDavid Rees return field_type.addressable_unit != type_definition.addressable_unit 224*99e0aae7SDavid Rees 225*99e0aae7SDavid Rees 226*99e0aae7SDavid Reesdef _field_may_have_null_byte_order(field, type_definition, ir): 227*99e0aae7SDavid Rees """Returns true if "Null" is a valid byte order for the given field.""" 228*99e0aae7SDavid Rees # If the field is one unit in length, then byte order does not matter. 229*99e0aae7SDavid Rees if (ir_util.is_constant(field.location.size) and 230*99e0aae7SDavid Rees ir_util.constant_value(field.location.size) == 1): 231*99e0aae7SDavid Rees return True 232*99e0aae7SDavid Rees unit = type_definition.addressable_unit 233*99e0aae7SDavid Rees # Otherwise, if the field's type is either a one-unit-sized type or an array 234*99e0aae7SDavid Rees # of a one-unit-sized type, then byte order does not matter. 235*99e0aae7SDavid Rees if (ir_util.fixed_size_of_type_in_bits(ir_util.get_base_type(field.type), ir) 236*99e0aae7SDavid Rees == unit): 237*99e0aae7SDavid Rees return True 238*99e0aae7SDavid Rees # In all other cases, byte order does matter. 239*99e0aae7SDavid Rees return False 240*99e0aae7SDavid Rees 241*99e0aae7SDavid Rees 242*99e0aae7SDavid Reesdef _add_missing_byte_order_attribute_on_field(field, type_definition, ir, 243*99e0aae7SDavid Rees defaults): 244*99e0aae7SDavid Rees """Adds missing byte_order attributes to fields that need them.""" 245*99e0aae7SDavid Rees if _field_needs_byte_order(field, type_definition, ir): 246*99e0aae7SDavid Rees byte_order_attr = ir_util.get_attribute(field.attribute, 247*99e0aae7SDavid Rees attributes.BYTE_ORDER) 248*99e0aae7SDavid Rees if byte_order_attr is None: 249*99e0aae7SDavid Rees if attributes.BYTE_ORDER in defaults: 250*99e0aae7SDavid Rees field.attribute.extend([defaults[attributes.BYTE_ORDER]]) 251*99e0aae7SDavid Rees elif _field_may_have_null_byte_order(field, type_definition, ir): 252*99e0aae7SDavid Rees field.attribute.extend( 253*99e0aae7SDavid Rees [_construct_string_attribute(attributes.BYTE_ORDER, "Null", 254*99e0aae7SDavid Rees field.source_location)]) 255*99e0aae7SDavid Rees 256*99e0aae7SDavid Rees 257*99e0aae7SDavid Reesdef _add_missing_back_ends_to_module(module): 258*99e0aae7SDavid Rees """Sets the expected_back_ends attribute for a module, if not already set.""" 259*99e0aae7SDavid Rees back_ends_attr = ir_util.get_attribute(module.attribute, attributes.BACK_ENDS) 260*99e0aae7SDavid Rees if back_ends_attr is None: 261*99e0aae7SDavid Rees module.attribute.extend( 262*99e0aae7SDavid Rees [_construct_string_attribute(attributes.BACK_ENDS, _DEFAULT_BACK_ENDS, 263*99e0aae7SDavid Rees module.source_location)]) 264*99e0aae7SDavid Rees 265*99e0aae7SDavid Rees 266*99e0aae7SDavid Reesdef _gather_expected_back_ends(module): 267*99e0aae7SDavid Rees """Captures the expected_back_ends attribute for `module`.""" 268*99e0aae7SDavid Rees back_ends_attr = ir_util.get_attribute(module.attribute, attributes.BACK_ENDS) 269*99e0aae7SDavid Rees back_ends_str = back_ends_attr.string_constant.text 270*99e0aae7SDavid Rees return { 271*99e0aae7SDavid Rees "expected_back_ends": {x.strip() for x in back_ends_str.split(",")} | {""} 272*99e0aae7SDavid Rees } 273*99e0aae7SDavid Rees 274*99e0aae7SDavid Rees 275*99e0aae7SDavid Reesdef _add_addressable_unit_to_external(external, type_definition): 276*99e0aae7SDavid Rees """Sets the addressable_unit field for an external TypeDefinition.""" 277*99e0aae7SDavid Rees # Strictly speaking, addressable_unit isn't an "attribute," but it's close 278*99e0aae7SDavid Rees # enough that it makes sense to handle it with attributes. 279*99e0aae7SDavid Rees del external # Unused. 280*99e0aae7SDavid Rees size = ir_util.get_integer_attribute(type_definition.attribute, 281*99e0aae7SDavid Rees attributes.ADDRESSABLE_UNIT_SIZE) 282*99e0aae7SDavid Rees if size == 1: 283*99e0aae7SDavid Rees type_definition.addressable_unit = ir_data.AddressableUnit.BIT 284*99e0aae7SDavid Rees elif size == 8: 285*99e0aae7SDavid Rees type_definition.addressable_unit = ir_data.AddressableUnit.BYTE 286*99e0aae7SDavid Rees # If the addressable_unit_size is not in (1, 8), it will be caught by 287*99e0aae7SDavid Rees # _verify_addressable_unit_attribute_on_external, below. 288*99e0aae7SDavid Rees 289*99e0aae7SDavid Rees 290*99e0aae7SDavid Reesdef _add_missing_width_and_sign_attributes_on_enum(enum, type_definition): 291*99e0aae7SDavid Rees """Sets the maximum_bits and is_signed attributes for an enum, if needed.""" 292*99e0aae7SDavid Rees max_bits_attr = ir_util.get_integer_attribute(type_definition.attribute, 293*99e0aae7SDavid Rees attributes.ENUM_MAXIMUM_BITS) 294*99e0aae7SDavid Rees if max_bits_attr is None: 295*99e0aae7SDavid Rees type_definition.attribute.extend([ 296*99e0aae7SDavid Rees _construct_integer_attribute(attributes.ENUM_MAXIMUM_BITS, 297*99e0aae7SDavid Rees _DEFAULT_ENUM_MAXIMUM_BITS, 298*99e0aae7SDavid Rees type_definition.source_location)]) 299*99e0aae7SDavid Rees signed_attr = ir_util.get_boolean_attribute(type_definition.attribute, 300*99e0aae7SDavid Rees attributes.IS_SIGNED) 301*99e0aae7SDavid Rees if signed_attr is None: 302*99e0aae7SDavid Rees for value in enum.value: 303*99e0aae7SDavid Rees numeric_value = ir_util.constant_value(value.value) 304*99e0aae7SDavid Rees if numeric_value < 0: 305*99e0aae7SDavid Rees is_signed = True 306*99e0aae7SDavid Rees break 307*99e0aae7SDavid Rees else: 308*99e0aae7SDavid Rees is_signed = False 309*99e0aae7SDavid Rees type_definition.attribute.extend([ 310*99e0aae7SDavid Rees _construct_boolean_attribute(attributes.IS_SIGNED, is_signed, 311*99e0aae7SDavid Rees type_definition.source_location)]) 312*99e0aae7SDavid Rees 313*99e0aae7SDavid Rees 314*99e0aae7SDavid Reesdef _verify_byte_order_attribute_on_field(field, type_definition, 315*99e0aae7SDavid Rees source_file_name, ir, errors): 316*99e0aae7SDavid Rees """Verifies the byte_order attribute on the given field.""" 317*99e0aae7SDavid Rees byte_order_attr = ir_util.get_attribute(field.attribute, 318*99e0aae7SDavid Rees attributes.BYTE_ORDER) 319*99e0aae7SDavid Rees field_needs_byte_order = _field_needs_byte_order(field, type_definition, ir) 320*99e0aae7SDavid Rees if byte_order_attr and not field_needs_byte_order: 321*99e0aae7SDavid Rees errors.append([error.error( 322*99e0aae7SDavid Rees source_file_name, byte_order_attr.source_location, 323*99e0aae7SDavid Rees "Attribute 'byte_order' not allowed on field which is not byte order " 324*99e0aae7SDavid Rees "dependent.")]) 325*99e0aae7SDavid Rees if not byte_order_attr and field_needs_byte_order: 326*99e0aae7SDavid Rees errors.append([error.error( 327*99e0aae7SDavid Rees source_file_name, field.source_location, 328*99e0aae7SDavid Rees "Attribute 'byte_order' required on field which is byte order " 329*99e0aae7SDavid Rees "dependent.")]) 330*99e0aae7SDavid Rees if (byte_order_attr and byte_order_attr.string_constant.text == "Null" and 331*99e0aae7SDavid Rees not _field_may_have_null_byte_order(field, type_definition, ir)): 332*99e0aae7SDavid Rees errors.append([error.error( 333*99e0aae7SDavid Rees source_file_name, byte_order_attr.source_location, 334*99e0aae7SDavid Rees "Attribute 'byte_order' may only be 'Null' for one-byte fields.")]) 335*99e0aae7SDavid Rees 336*99e0aae7SDavid Rees 337*99e0aae7SDavid Reesdef _verify_requires_attribute_on_field(field, source_file_name, ir, errors): 338*99e0aae7SDavid Rees """Verifies that [requires] is valid on the given field.""" 339*99e0aae7SDavid Rees requires_attr = ir_util.get_attribute(field.attribute, attributes.REQUIRES) 340*99e0aae7SDavid Rees if not requires_attr: 341*99e0aae7SDavid Rees return 342*99e0aae7SDavid Rees if ir_util.field_is_virtual(field): 343*99e0aae7SDavid Rees field_expression_type = field.read_transform.type 344*99e0aae7SDavid Rees else: 345*99e0aae7SDavid Rees if not field.type.HasField("atomic_type"): 346*99e0aae7SDavid Rees errors.append([ 347*99e0aae7SDavid Rees error.error(source_file_name, requires_attr.source_location, 348*99e0aae7SDavid Rees "Attribute 'requires' is only allowed on integer, " 349*99e0aae7SDavid Rees "enumeration, or boolean fields, not arrays."), 350*99e0aae7SDavid Rees error.note(source_file_name, field.type.source_location, 351*99e0aae7SDavid Rees "Field type."), 352*99e0aae7SDavid Rees ]) 353*99e0aae7SDavid Rees return 354*99e0aae7SDavid Rees field_type = ir_util.find_object(field.type.atomic_type.reference, ir) 355*99e0aae7SDavid Rees assert field_type, "Field type should be non-None after name resolution." 356*99e0aae7SDavid Rees field_expression_type = ( 357*99e0aae7SDavid Rees type_check.unbounded_expression_type_for_physical_type(field_type)) 358*99e0aae7SDavid Rees if field_expression_type.WhichOneof("type") not in ( 359*99e0aae7SDavid Rees "integer", "enumeration", "boolean"): 360*99e0aae7SDavid Rees errors.append([error.error( 361*99e0aae7SDavid Rees source_file_name, requires_attr.source_location, 362*99e0aae7SDavid Rees "Attribute 'requires' is only allowed on integer, enumeration, or " 363*99e0aae7SDavid Rees "boolean fields.")]) 364*99e0aae7SDavid Rees 365*99e0aae7SDavid Rees 366*99e0aae7SDavid Reesdef _verify_addressable_unit_attribute_on_external(external, type_definition, 367*99e0aae7SDavid Rees source_file_name, errors): 368*99e0aae7SDavid Rees """Verifies the addressable_unit_size attribute on an external.""" 369*99e0aae7SDavid Rees del external # Unused. 370*99e0aae7SDavid Rees addressable_unit_size_attr = ir_util.get_integer_attribute( 371*99e0aae7SDavid Rees type_definition.attribute, attributes.ADDRESSABLE_UNIT_SIZE) 372*99e0aae7SDavid Rees if addressable_unit_size_attr is None: 373*99e0aae7SDavid Rees errors.append([error.error( 374*99e0aae7SDavid Rees source_file_name, type_definition.source_location, 375*99e0aae7SDavid Rees "Expected '{}' attribute for external type.".format( 376*99e0aae7SDavid Rees attributes.ADDRESSABLE_UNIT_SIZE))]) 377*99e0aae7SDavid Rees elif addressable_unit_size_attr not in (1, 8): 378*99e0aae7SDavid Rees errors.append([ 379*99e0aae7SDavid Rees error.error(source_file_name, type_definition.source_location, 380*99e0aae7SDavid Rees "Only values '1' (bit) and '8' (byte) are allowed for the " 381*99e0aae7SDavid Rees "'{}' attribute".format(attributes.ADDRESSABLE_UNIT_SIZE)) 382*99e0aae7SDavid Rees ]) 383*99e0aae7SDavid Rees 384*99e0aae7SDavid Rees 385*99e0aae7SDavid Reesdef _verify_width_attribute_on_enum(enum, type_definition, source_file_name, 386*99e0aae7SDavid Rees errors): 387*99e0aae7SDavid Rees """Verifies the maximum_bits attribute for an enum TypeDefinition.""" 388*99e0aae7SDavid Rees max_bits_value = ir_util.get_integer_attribute(type_definition.attribute, 389*99e0aae7SDavid Rees attributes.ENUM_MAXIMUM_BITS) 390*99e0aae7SDavid Rees # The attribute should already have been defaulted, if not originally present. 391*99e0aae7SDavid Rees assert max_bits_value is not None, "maximum_bits not set" 392*99e0aae7SDavid Rees if max_bits_value > 64 or max_bits_value < 1: 393*99e0aae7SDavid Rees max_bits_attr = ir_util.get_attribute(type_definition.attribute, 394*99e0aae7SDavid Rees attributes.ENUM_MAXIMUM_BITS) 395*99e0aae7SDavid Rees errors.append([ 396*99e0aae7SDavid Rees error.error(source_file_name, max_bits_attr.source_location, 397*99e0aae7SDavid Rees "'maximum_bits' on an 'enum' must be between 1 and 64.") 398*99e0aae7SDavid Rees ]) 399*99e0aae7SDavid Rees 400*99e0aae7SDavid Rees 401*99e0aae7SDavid Reesdef _add_missing_attributes_on_ir(ir): 402*99e0aae7SDavid Rees """Adds missing attributes in a complete IR.""" 403*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 404*99e0aae7SDavid Rees ir, [ir_data.Module], _add_missing_back_ends_to_module) 405*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 406*99e0aae7SDavid Rees ir, [ir_data.External], _add_addressable_unit_to_external) 407*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 408*99e0aae7SDavid Rees ir, [ir_data.Enum], _add_missing_width_and_sign_attributes_on_enum) 409*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 410*99e0aae7SDavid Rees ir, [ir_data.Structure], _add_missing_size_attributes_on_structure, 411*99e0aae7SDavid Rees incidental_actions={ 412*99e0aae7SDavid Rees ir_data.Module: attribute_util.gather_default_attributes, 413*99e0aae7SDavid Rees ir_data.TypeDefinition: attribute_util.gather_default_attributes, 414*99e0aae7SDavid Rees ir_data.Field: attribute_util.gather_default_attributes, 415*99e0aae7SDavid Rees }, 416*99e0aae7SDavid Rees parameters={"defaults": {}}) 417*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 418*99e0aae7SDavid Rees ir, [ir_data.Field], _add_missing_byte_order_attribute_on_field, 419*99e0aae7SDavid Rees incidental_actions={ 420*99e0aae7SDavid Rees ir_data.Module: attribute_util.gather_default_attributes, 421*99e0aae7SDavid Rees ir_data.TypeDefinition: attribute_util.gather_default_attributes, 422*99e0aae7SDavid Rees ir_data.Field: attribute_util.gather_default_attributes, 423*99e0aae7SDavid Rees }, 424*99e0aae7SDavid Rees parameters={"defaults": {}}) 425*99e0aae7SDavid Rees return [] 426*99e0aae7SDavid Rees 427*99e0aae7SDavid Rees 428*99e0aae7SDavid Reesdef _verify_field_attributes(field, type_definition, source_file_name, ir, 429*99e0aae7SDavid Rees errors): 430*99e0aae7SDavid Rees _verify_byte_order_attribute_on_field(field, type_definition, 431*99e0aae7SDavid Rees source_file_name, ir, errors) 432*99e0aae7SDavid Rees _verify_requires_attribute_on_field(field, source_file_name, ir, errors) 433*99e0aae7SDavid Rees 434*99e0aae7SDavid Rees 435*99e0aae7SDavid Reesdef _verify_back_end_attributes(attribute, expected_back_ends, source_file_name, 436*99e0aae7SDavid Rees ir, errors): 437*99e0aae7SDavid Rees back_end_text = ir_data_utils.reader(attribute).back_end.text 438*99e0aae7SDavid Rees if back_end_text not in expected_back_ends: 439*99e0aae7SDavid Rees expected_back_ends_for_error = expected_back_ends - {""} 440*99e0aae7SDavid Rees errors.append([error.error( 441*99e0aae7SDavid Rees source_file_name, attribute.back_end.source_location, 442*99e0aae7SDavid Rees "Back end specifier '{back_end}' does not match any expected back end " 443*99e0aae7SDavid Rees "specifier for this file: '{expected_back_ends}'. Add or update the " 444*99e0aae7SDavid Rees "'[expected_back_ends: \"{new_expected_back_ends}\"]' attribute at the " 445*99e0aae7SDavid Rees "file level if this back end specifier is intentional.".format( 446*99e0aae7SDavid Rees back_end=attribute.back_end.text, 447*99e0aae7SDavid Rees expected_back_ends="', '".join( 448*99e0aae7SDavid Rees sorted(expected_back_ends_for_error)), 449*99e0aae7SDavid Rees new_expected_back_ends=", ".join( 450*99e0aae7SDavid Rees sorted(expected_back_ends_for_error | {back_end_text})), 451*99e0aae7SDavid Rees ))]) 452*99e0aae7SDavid Rees 453*99e0aae7SDavid Rees 454*99e0aae7SDavid Reesdef _verify_attributes_on_ir(ir): 455*99e0aae7SDavid Rees """Verifies attributes in a complete IR.""" 456*99e0aae7SDavid Rees errors = [] 457*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 458*99e0aae7SDavid Rees ir, [ir_data.Attribute], _verify_back_end_attributes, 459*99e0aae7SDavid Rees incidental_actions={ 460*99e0aae7SDavid Rees ir_data.Module: _gather_expected_back_ends, 461*99e0aae7SDavid Rees }, 462*99e0aae7SDavid Rees parameters={"errors": errors}) 463*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 464*99e0aae7SDavid Rees ir, [ir_data.Structure], _verify_size_attributes_on_structure, 465*99e0aae7SDavid Rees parameters={"errors": errors}) 466*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 467*99e0aae7SDavid Rees ir, [ir_data.Enum], _verify_width_attribute_on_enum, 468*99e0aae7SDavid Rees parameters={"errors": errors}) 469*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 470*99e0aae7SDavid Rees ir, [ir_data.External], _verify_addressable_unit_attribute_on_external, 471*99e0aae7SDavid Rees parameters={"errors": errors}) 472*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 473*99e0aae7SDavid Rees ir, [ir_data.Field], _verify_field_attributes, 474*99e0aae7SDavid Rees parameters={"errors": errors}) 475*99e0aae7SDavid Rees return errors 476*99e0aae7SDavid Rees 477*99e0aae7SDavid Rees 478*99e0aae7SDavid Reesdef normalize_and_verify(ir): 479*99e0aae7SDavid Rees """Performs various normalizations and verifications on ir. 480*99e0aae7SDavid Rees 481*99e0aae7SDavid Rees Checks for duplicate attributes. 482*99e0aae7SDavid Rees 483*99e0aae7SDavid Rees Adds fixed_size_in_bits and addressable_unit_size attributes to types when 484*99e0aae7SDavid Rees they are missing, and checks their correctness when they are not missing. 485*99e0aae7SDavid Rees 486*99e0aae7SDavid Rees Arguments: 487*99e0aae7SDavid Rees ir: The IR object to normalize. 488*99e0aae7SDavid Rees 489*99e0aae7SDavid Rees Returns: 490*99e0aae7SDavid Rees A list of validation errors, or an empty list if no errors were encountered. 491*99e0aae7SDavid Rees """ 492*99e0aae7SDavid Rees errors = attribute_util.check_attributes_in_ir( 493*99e0aae7SDavid Rees ir, 494*99e0aae7SDavid Rees types=_ATTRIBUTE_TYPES, 495*99e0aae7SDavid Rees module_attributes=_MODULE_ATTRIBUTES, 496*99e0aae7SDavid Rees struct_attributes=_STRUCT_ATTRIBUTES, 497*99e0aae7SDavid Rees bits_attributes=_BITS_ATTRIBUTES, 498*99e0aae7SDavid Rees enum_attributes=_ENUM_ATTRIBUTES, 499*99e0aae7SDavid Rees external_attributes=_EXTERNAL_ATTRIBUTES, 500*99e0aae7SDavid Rees structure_virtual_field_attributes=_STRUCT_VIRTUAL_FIELD_ATTRIBUTES, 501*99e0aae7SDavid Rees structure_physical_field_attributes=_STRUCT_PHYSICAL_FIELD_ATTRIBUTES) 502*99e0aae7SDavid Rees if errors: 503*99e0aae7SDavid Rees return errors 504*99e0aae7SDavid Rees _add_missing_attributes_on_ir(ir) 505*99e0aae7SDavid Rees return _verify_attributes_on_ir(ir) 506