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"""Utility functions for reading and manipulating Emboss IR.""" 16*99e0aae7SDavid Rees 17*99e0aae7SDavid Reesimport operator 18*99e0aae7SDavid Rees 19*99e0aae7SDavid Reesfrom compiler.util import ir_data 20*99e0aae7SDavid Reesfrom compiler.util import ir_data_utils 21*99e0aae7SDavid Rees 22*99e0aae7SDavid Rees 23*99e0aae7SDavid Rees_FIXED_SIZE_ATTRIBUTE = "fixed_size_in_bits" 24*99e0aae7SDavid Rees 25*99e0aae7SDavid Rees 26*99e0aae7SDavid Reesdef get_attribute(attribute_list, name): 27*99e0aae7SDavid Rees """Finds name in attribute_list and returns a AttributeValue or None.""" 28*99e0aae7SDavid Rees if not attribute_list: 29*99e0aae7SDavid Rees return None 30*99e0aae7SDavid Rees attribute_value = None 31*99e0aae7SDavid Rees for attr in attribute_list: 32*99e0aae7SDavid Rees if attr.name.text == name and not attr.is_default: 33*99e0aae7SDavid Rees assert attribute_value is None, 'Duplicate attribute "{}".'.format(name) 34*99e0aae7SDavid Rees attribute_value = attr.value 35*99e0aae7SDavid Rees return attribute_value 36*99e0aae7SDavid Rees 37*99e0aae7SDavid Rees 38*99e0aae7SDavid Reesdef get_boolean_attribute(attribute_list, name, default_value=None): 39*99e0aae7SDavid Rees """Returns the boolean value of an attribute, if any, or default_value. 40*99e0aae7SDavid Rees 41*99e0aae7SDavid Rees Arguments: 42*99e0aae7SDavid Rees attribute_list: A list of attributes to search. 43*99e0aae7SDavid Rees name: The name of the desired attribute. 44*99e0aae7SDavid Rees default_value: A value to return if name is not found in attribute_list, 45*99e0aae7SDavid Rees or the attribute does not have a boolean value. 46*99e0aae7SDavid Rees 47*99e0aae7SDavid Rees Returns: 48*99e0aae7SDavid Rees The boolean value of the requested attribute, or default_value if the 49*99e0aae7SDavid Rees requested attribute is not found or has a non-boolean value. 50*99e0aae7SDavid Rees """ 51*99e0aae7SDavid Rees attribute_value = get_attribute(attribute_list, name) 52*99e0aae7SDavid Rees if (not attribute_value or 53*99e0aae7SDavid Rees not attribute_value.expression.HasField("boolean_constant")): 54*99e0aae7SDavid Rees return default_value 55*99e0aae7SDavid Rees return attribute_value.expression.boolean_constant.value 56*99e0aae7SDavid Rees 57*99e0aae7SDavid Rees 58*99e0aae7SDavid Reesdef get_integer_attribute(attribute_list, name, default_value=None): 59*99e0aae7SDavid Rees """Returns the integer value of an attribute, if any, or default_value. 60*99e0aae7SDavid Rees 61*99e0aae7SDavid Rees Arguments: 62*99e0aae7SDavid Rees attribute_list: A list of attributes to search. 63*99e0aae7SDavid Rees name: The name of the desired attribute. 64*99e0aae7SDavid Rees default_value: A value to return if name is not found in attribute_list, 65*99e0aae7SDavid Rees or the attribute does not have an integer value. 66*99e0aae7SDavid Rees 67*99e0aae7SDavid Rees Returns: 68*99e0aae7SDavid Rees The integer value of the requested attribute, or default_value if the 69*99e0aae7SDavid Rees requested attribute is not found or has a non-integer value. 70*99e0aae7SDavid Rees """ 71*99e0aae7SDavid Rees attribute_value = get_attribute(attribute_list, name) 72*99e0aae7SDavid Rees if (not attribute_value or 73*99e0aae7SDavid Rees attribute_value.expression.type.WhichOneof("type") != "integer" or 74*99e0aae7SDavid Rees not is_constant(attribute_value.expression)): 75*99e0aae7SDavid Rees return default_value 76*99e0aae7SDavid Rees return constant_value(attribute_value.expression) 77*99e0aae7SDavid Rees 78*99e0aae7SDavid Rees 79*99e0aae7SDavid Reesdef is_constant(expression, bindings=None): 80*99e0aae7SDavid Rees return constant_value(expression, bindings) is not None 81*99e0aae7SDavid Rees 82*99e0aae7SDavid Rees 83*99e0aae7SDavid Reesdef is_constant_type(expression_type): 84*99e0aae7SDavid Rees """Returns True if expression_type is inhabited by a single value.""" 85*99e0aae7SDavid Rees expression_type = ir_data_utils.reader(expression_type) 86*99e0aae7SDavid Rees return (expression_type.integer.modulus == "infinity" or 87*99e0aae7SDavid Rees expression_type.boolean.HasField("value") or 88*99e0aae7SDavid Rees expression_type.enumeration.HasField("value")) 89*99e0aae7SDavid Rees 90*99e0aae7SDavid Rees 91*99e0aae7SDavid Reesdef constant_value(expression, bindings=None): 92*99e0aae7SDavid Rees """Evaluates expression with the given bindings.""" 93*99e0aae7SDavid Rees if expression is None: 94*99e0aae7SDavid Rees return None 95*99e0aae7SDavid Rees expression = ir_data_utils.reader(expression) 96*99e0aae7SDavid Rees if expression.WhichOneof("expression") == "constant": 97*99e0aae7SDavid Rees return int(expression.constant.value or 0) 98*99e0aae7SDavid Rees elif expression.WhichOneof("expression") == "constant_reference": 99*99e0aae7SDavid Rees # We can't look up the constant reference without the IR, but by the time 100*99e0aae7SDavid Rees # constant_value is called, the actual values should have been propagated to 101*99e0aae7SDavid Rees # the type information. 102*99e0aae7SDavid Rees if expression.type.WhichOneof("type") == "integer": 103*99e0aae7SDavid Rees assert expression.type.integer.modulus == "infinity" 104*99e0aae7SDavid Rees return int(expression.type.integer.modular_value) 105*99e0aae7SDavid Rees elif expression.type.WhichOneof("type") == "boolean": 106*99e0aae7SDavid Rees assert expression.type.boolean.HasField("value") 107*99e0aae7SDavid Rees return expression.type.boolean.value 108*99e0aae7SDavid Rees elif expression.type.WhichOneof("type") == "enumeration": 109*99e0aae7SDavid Rees assert expression.type.enumeration.HasField("value") 110*99e0aae7SDavid Rees return int(expression.type.enumeration.value) 111*99e0aae7SDavid Rees else: 112*99e0aae7SDavid Rees assert False, "Unexpected expression type {}".format( 113*99e0aae7SDavid Rees expression.type.WhichOneof("type")) 114*99e0aae7SDavid Rees elif expression.WhichOneof("expression") == "function": 115*99e0aae7SDavid Rees return _constant_value_of_function(expression.function, bindings) 116*99e0aae7SDavid Rees elif expression.WhichOneof("expression") == "field_reference": 117*99e0aae7SDavid Rees return None 118*99e0aae7SDavid Rees elif expression.WhichOneof("expression") == "boolean_constant": 119*99e0aae7SDavid Rees return expression.boolean_constant.value 120*99e0aae7SDavid Rees elif expression.WhichOneof("expression") == "builtin_reference": 121*99e0aae7SDavid Rees name = expression.builtin_reference.canonical_name.object_path[0] 122*99e0aae7SDavid Rees if bindings and name in bindings: 123*99e0aae7SDavid Rees return bindings[name] 124*99e0aae7SDavid Rees else: 125*99e0aae7SDavid Rees return None 126*99e0aae7SDavid Rees elif expression.WhichOneof("expression") is None: 127*99e0aae7SDavid Rees return None 128*99e0aae7SDavid Rees else: 129*99e0aae7SDavid Rees assert False, "Unexpected expression kind {}".format( 130*99e0aae7SDavid Rees expression.WhichOneof("expression")) 131*99e0aae7SDavid Rees 132*99e0aae7SDavid Rees 133*99e0aae7SDavid Reesdef _constant_value_of_function(function, bindings): 134*99e0aae7SDavid Rees """Returns the constant value of evaluating `function`, or None.""" 135*99e0aae7SDavid Rees values = [constant_value(arg, bindings) for arg in function.args] 136*99e0aae7SDavid Rees # Expressions like `$is_statically_sized && 1 <= $static_size_in_bits <= 64` 137*99e0aae7SDavid Rees # should return False, not None, if `$is_statically_sized` is false, even 138*99e0aae7SDavid Rees # though `$static_size_in_bits` is unknown. 139*99e0aae7SDavid Rees # 140*99e0aae7SDavid Rees # The easiest way to allow this is to use a three-way logic chart for each; 141*99e0aae7SDavid Rees # specifically: 142*99e0aae7SDavid Rees # 143*99e0aae7SDavid Rees # AND: True False Unknown 144*99e0aae7SDavid Rees # +-------------------------- 145*99e0aae7SDavid Rees # True | True False Unknown 146*99e0aae7SDavid Rees # False | False False False 147*99e0aae7SDavid Rees # Unknown | Unknown False Unknown 148*99e0aae7SDavid Rees # 149*99e0aae7SDavid Rees # OR: True False Unknown 150*99e0aae7SDavid Rees # +-------------------------- 151*99e0aae7SDavid Rees # True | True True True 152*99e0aae7SDavid Rees # False | True False Unknown 153*99e0aae7SDavid Rees # Unknown | True Unknown Unknown 154*99e0aae7SDavid Rees # 155*99e0aae7SDavid Rees # This raises the question of just how many constant-from-nonconstant 156*99e0aae7SDavid Rees # expressions Emboss should support. There are, after all, a vast number of 157*99e0aae7SDavid Rees # constant expression patterns built from non-constant subexpressions, such as 158*99e0aae7SDavid Rees # `0 * X` or `X == X` or `3 * X == X + X + X`. I (bolms@) am not implementing 159*99e0aae7SDavid Rees # any further special cases because I do not see any practical use for them. 160*99e0aae7SDavid Rees if function.function == ir_data.FunctionMapping.UNKNOWN: 161*99e0aae7SDavid Rees return None 162*99e0aae7SDavid Rees if function.function == ir_data.FunctionMapping.AND: 163*99e0aae7SDavid Rees if any(value is False for value in values): 164*99e0aae7SDavid Rees return False 165*99e0aae7SDavid Rees elif any(value is None for value in values): 166*99e0aae7SDavid Rees return None 167*99e0aae7SDavid Rees else: 168*99e0aae7SDavid Rees return True 169*99e0aae7SDavid Rees elif function.function == ir_data.FunctionMapping.OR: 170*99e0aae7SDavid Rees if any(value is True for value in values): 171*99e0aae7SDavid Rees return True 172*99e0aae7SDavid Rees elif any(value is None for value in values): 173*99e0aae7SDavid Rees return None 174*99e0aae7SDavid Rees else: 175*99e0aae7SDavid Rees return False 176*99e0aae7SDavid Rees elif function.function == ir_data.FunctionMapping.CHOICE: 177*99e0aae7SDavid Rees if values[0] is None: 178*99e0aae7SDavid Rees return None 179*99e0aae7SDavid Rees else: 180*99e0aae7SDavid Rees return values[1] if values[0] else values[2] 181*99e0aae7SDavid Rees # Other than the logical operators and choice operator, the result of any 182*99e0aae7SDavid Rees # function on an unknown value is, itself, considered unknown. 183*99e0aae7SDavid Rees if any(value is None for value in values): 184*99e0aae7SDavid Rees return None 185*99e0aae7SDavid Rees functions = { 186*99e0aae7SDavid Rees ir_data.FunctionMapping.ADDITION: operator.add, 187*99e0aae7SDavid Rees ir_data.FunctionMapping.SUBTRACTION: operator.sub, 188*99e0aae7SDavid Rees ir_data.FunctionMapping.MULTIPLICATION: operator.mul, 189*99e0aae7SDavid Rees ir_data.FunctionMapping.EQUALITY: operator.eq, 190*99e0aae7SDavid Rees ir_data.FunctionMapping.INEQUALITY: operator.ne, 191*99e0aae7SDavid Rees ir_data.FunctionMapping.LESS: operator.lt, 192*99e0aae7SDavid Rees ir_data.FunctionMapping.LESS_OR_EQUAL: operator.le, 193*99e0aae7SDavid Rees ir_data.FunctionMapping.GREATER: operator.gt, 194*99e0aae7SDavid Rees ir_data.FunctionMapping.GREATER_OR_EQUAL: operator.ge, 195*99e0aae7SDavid Rees # Python's max([1, 2]) == 2; max(1, 2) == 2; max([1]) == 1; but max(1) 196*99e0aae7SDavid Rees # throws a TypeError ("'int' object is not iterable"). 197*99e0aae7SDavid Rees ir_data.FunctionMapping.MAXIMUM: lambda *x: max(x), 198*99e0aae7SDavid Rees } 199*99e0aae7SDavid Rees return functions[function.function](*values) 200*99e0aae7SDavid Rees 201*99e0aae7SDavid Rees 202*99e0aae7SDavid Reesdef _hashable_form_of_name(name): 203*99e0aae7SDavid Rees return (name.module_file,) + tuple(name.object_path) 204*99e0aae7SDavid Rees 205*99e0aae7SDavid Rees 206*99e0aae7SDavid Reesdef hashable_form_of_reference(reference): 207*99e0aae7SDavid Rees """Returns a representation of reference that can be used as a dict key. 208*99e0aae7SDavid Rees 209*99e0aae7SDavid Rees Arguments: 210*99e0aae7SDavid Rees reference: An ir_data.Reference or ir_data.NameDefinition. 211*99e0aae7SDavid Rees 212*99e0aae7SDavid Rees Returns: 213*99e0aae7SDavid Rees A tuple of the module_file and object_path. 214*99e0aae7SDavid Rees """ 215*99e0aae7SDavid Rees return _hashable_form_of_name(reference.canonical_name) 216*99e0aae7SDavid Rees 217*99e0aae7SDavid Rees 218*99e0aae7SDavid Reesdef hashable_form_of_field_reference(field_reference): 219*99e0aae7SDavid Rees """Returns a representation of field_reference that can be used as a dict key. 220*99e0aae7SDavid Rees 221*99e0aae7SDavid Rees Arguments: 222*99e0aae7SDavid Rees field_reference: An ir_data.FieldReference 223*99e0aae7SDavid Rees 224*99e0aae7SDavid Rees Returns: 225*99e0aae7SDavid Rees A tuple of tuples of the module_files and object_paths. 226*99e0aae7SDavid Rees """ 227*99e0aae7SDavid Rees return tuple(_hashable_form_of_name(reference.canonical_name) 228*99e0aae7SDavid Rees for reference in field_reference.path) 229*99e0aae7SDavid Rees 230*99e0aae7SDavid Rees 231*99e0aae7SDavid Reesdef is_array(type_ir): 232*99e0aae7SDavid Rees """Returns true if type_ir is an array type.""" 233*99e0aae7SDavid Rees return type_ir.HasField("array_type") 234*99e0aae7SDavid Rees 235*99e0aae7SDavid Rees 236*99e0aae7SDavid Reesdef _find_path_in_structure_field(path, field): 237*99e0aae7SDavid Rees if not path: 238*99e0aae7SDavid Rees return field 239*99e0aae7SDavid Rees return None 240*99e0aae7SDavid Rees 241*99e0aae7SDavid Rees 242*99e0aae7SDavid Reesdef _find_path_in_structure(path, type_definition): 243*99e0aae7SDavid Rees for field in type_definition.structure.field: 244*99e0aae7SDavid Rees if field.name.name.text == path[0]: 245*99e0aae7SDavid Rees return _find_path_in_structure_field(path[1:], field) 246*99e0aae7SDavid Rees return None 247*99e0aae7SDavid Rees 248*99e0aae7SDavid Rees 249*99e0aae7SDavid Reesdef _find_path_in_enumeration(path, type_definition): 250*99e0aae7SDavid Rees if len(path) != 1: 251*99e0aae7SDavid Rees return None 252*99e0aae7SDavid Rees for value in type_definition.enumeration.value: 253*99e0aae7SDavid Rees if value.name.name.text == path[0]: 254*99e0aae7SDavid Rees return value 255*99e0aae7SDavid Rees return None 256*99e0aae7SDavid Rees 257*99e0aae7SDavid Rees 258*99e0aae7SDavid Reesdef _find_path_in_parameters(path, type_definition): 259*99e0aae7SDavid Rees if len(path) > 1 or not type_definition.HasField("runtime_parameter"): 260*99e0aae7SDavid Rees return None 261*99e0aae7SDavid Rees for parameter in type_definition.runtime_parameter: 262*99e0aae7SDavid Rees if ir_data_utils.reader(parameter).name.name.text == path[0]: 263*99e0aae7SDavid Rees return parameter 264*99e0aae7SDavid Rees return None 265*99e0aae7SDavid Rees 266*99e0aae7SDavid Rees 267*99e0aae7SDavid Reesdef _find_path_in_type_definition(path, type_definition): 268*99e0aae7SDavid Rees """Finds the object with the given path in the given type_definition.""" 269*99e0aae7SDavid Rees if not path: 270*99e0aae7SDavid Rees return type_definition 271*99e0aae7SDavid Rees obj = _find_path_in_parameters(path, type_definition) 272*99e0aae7SDavid Rees if obj: 273*99e0aae7SDavid Rees return obj 274*99e0aae7SDavid Rees if type_definition.HasField("structure"): 275*99e0aae7SDavid Rees obj = _find_path_in_structure(path, type_definition) 276*99e0aae7SDavid Rees elif type_definition.HasField("enumeration"): 277*99e0aae7SDavid Rees obj = _find_path_in_enumeration(path, type_definition) 278*99e0aae7SDavid Rees if obj: 279*99e0aae7SDavid Rees return obj 280*99e0aae7SDavid Rees else: 281*99e0aae7SDavid Rees return _find_path_in_type_list(path, type_definition.subtype or []) 282*99e0aae7SDavid Rees 283*99e0aae7SDavid Rees 284*99e0aae7SDavid Reesdef _find_path_in_type_list(path, type_list): 285*99e0aae7SDavid Rees for type_definition in type_list: 286*99e0aae7SDavid Rees if type_definition.name.name.text == path[0]: 287*99e0aae7SDavid Rees return _find_path_in_type_definition(path[1:], type_definition) 288*99e0aae7SDavid Rees return None 289*99e0aae7SDavid Rees 290*99e0aae7SDavid Rees 291*99e0aae7SDavid Reesdef _find_path_in_module(path, module_ir): 292*99e0aae7SDavid Rees if not path: 293*99e0aae7SDavid Rees return module_ir 294*99e0aae7SDavid Rees return _find_path_in_type_list(path, module_ir.type) 295*99e0aae7SDavid Rees 296*99e0aae7SDavid Rees 297*99e0aae7SDavid Reesdef find_object_or_none(name, ir): 298*99e0aae7SDavid Rees """Finds the object with the given canonical name, if it exists..""" 299*99e0aae7SDavid Rees if (isinstance(name, ir_data.Reference) or 300*99e0aae7SDavid Rees isinstance(name, ir_data.NameDefinition)): 301*99e0aae7SDavid Rees path = _hashable_form_of_name(name.canonical_name) 302*99e0aae7SDavid Rees elif isinstance(name, ir_data.CanonicalName): 303*99e0aae7SDavid Rees path = _hashable_form_of_name(name) 304*99e0aae7SDavid Rees else: 305*99e0aae7SDavid Rees path = name 306*99e0aae7SDavid Rees 307*99e0aae7SDavid Rees for module in ir.module: 308*99e0aae7SDavid Rees if module.source_file_name == path[0]: 309*99e0aae7SDavid Rees return _find_path_in_module(path[1:], module) 310*99e0aae7SDavid Rees 311*99e0aae7SDavid Rees return None 312*99e0aae7SDavid Rees 313*99e0aae7SDavid Rees 314*99e0aae7SDavid Reesdef find_object(name, ir): 315*99e0aae7SDavid Rees """Finds the IR of the type, field, or value with the given canonical name.""" 316*99e0aae7SDavid Rees result = find_object_or_none(name, ir) 317*99e0aae7SDavid Rees assert result is not None, "Bad reference {}".format(name) 318*99e0aae7SDavid Rees return result 319*99e0aae7SDavid Rees 320*99e0aae7SDavid Rees 321*99e0aae7SDavid Reesdef find_parent_object(name, ir): 322*99e0aae7SDavid Rees """Finds the parent object of the object with the given canonical name.""" 323*99e0aae7SDavid Rees if (isinstance(name, ir_data.Reference) or 324*99e0aae7SDavid Rees isinstance(name, ir_data.NameDefinition)): 325*99e0aae7SDavid Rees path = _hashable_form_of_name(name.canonical_name) 326*99e0aae7SDavid Rees elif isinstance(name, ir_data.CanonicalName): 327*99e0aae7SDavid Rees path = _hashable_form_of_name(name) 328*99e0aae7SDavid Rees else: 329*99e0aae7SDavid Rees path = name 330*99e0aae7SDavid Rees return find_object(path[:-1], ir) 331*99e0aae7SDavid Rees 332*99e0aae7SDavid Rees 333*99e0aae7SDavid Reesdef get_base_type(type_ir): 334*99e0aae7SDavid Rees """Returns the base type of the given type. 335*99e0aae7SDavid Rees 336*99e0aae7SDavid Rees Arguments: 337*99e0aae7SDavid Rees type_ir: IR of a type reference. 338*99e0aae7SDavid Rees 339*99e0aae7SDavid Rees Returns: 340*99e0aae7SDavid Rees If type_ir corresponds to an atomic type (like "UInt"), returns type_ir. If 341*99e0aae7SDavid Rees type_ir corresponds to an array type (like "UInt:8[12]" or "Square[8][8]"), 342*99e0aae7SDavid Rees returns the type after stripping off the array types ("UInt" or "Square"). 343*99e0aae7SDavid Rees """ 344*99e0aae7SDavid Rees while type_ir.HasField("array_type"): 345*99e0aae7SDavid Rees type_ir = type_ir.array_type.base_type 346*99e0aae7SDavid Rees assert type_ir.HasField("atomic_type"), ( 347*99e0aae7SDavid Rees "Unknown kind of type {}".format(type_ir)) 348*99e0aae7SDavid Rees return type_ir 349*99e0aae7SDavid Rees 350*99e0aae7SDavid Rees 351*99e0aae7SDavid Reesdef fixed_size_of_type_in_bits(type_ir, ir): 352*99e0aae7SDavid Rees """Returns the fixed, known size for the given type, in bits, or None. 353*99e0aae7SDavid Rees 354*99e0aae7SDavid Rees Arguments: 355*99e0aae7SDavid Rees type_ir: The IR of a type. 356*99e0aae7SDavid Rees ir: A complete IR, used to resolve references to types. 357*99e0aae7SDavid Rees 358*99e0aae7SDavid Rees Returns: 359*99e0aae7SDavid Rees size if the size of the type can be determined, otherwise None. 360*99e0aae7SDavid Rees """ 361*99e0aae7SDavid Rees array_multiplier = 1 362*99e0aae7SDavid Rees while type_ir.HasField("array_type"): 363*99e0aae7SDavid Rees if type_ir.array_type.WhichOneof("size") == "automatic": 364*99e0aae7SDavid Rees return None 365*99e0aae7SDavid Rees else: 366*99e0aae7SDavid Rees assert type_ir.array_type.WhichOneof("size") == "element_count", ( 367*99e0aae7SDavid Rees 'Expected array size to be "automatic" or "element_count".') 368*99e0aae7SDavid Rees element_count = type_ir.array_type.element_count 369*99e0aae7SDavid Rees if not is_constant(element_count): 370*99e0aae7SDavid Rees return None 371*99e0aae7SDavid Rees else: 372*99e0aae7SDavid Rees array_multiplier *= constant_value(element_count) 373*99e0aae7SDavid Rees assert not type_ir.HasField("size_in_bits"), ( 374*99e0aae7SDavid Rees "TODO(bolms): implement explicitly-sized arrays") 375*99e0aae7SDavid Rees type_ir = type_ir.array_type.base_type 376*99e0aae7SDavid Rees assert type_ir.HasField("atomic_type"), "Unexpected type!" 377*99e0aae7SDavid Rees if type_ir.HasField("size_in_bits"): 378*99e0aae7SDavid Rees size = constant_value(type_ir.size_in_bits) 379*99e0aae7SDavid Rees else: 380*99e0aae7SDavid Rees type_definition = find_object(type_ir.atomic_type.reference, ir) 381*99e0aae7SDavid Rees size_attr = get_attribute(type_definition.attribute, _FIXED_SIZE_ATTRIBUTE) 382*99e0aae7SDavid Rees if not size_attr: 383*99e0aae7SDavid Rees return None 384*99e0aae7SDavid Rees size = constant_value(size_attr.expression) 385*99e0aae7SDavid Rees return size * array_multiplier 386*99e0aae7SDavid Rees 387*99e0aae7SDavid Rees 388*99e0aae7SDavid Reesdef field_is_virtual(field_ir): 389*99e0aae7SDavid Rees """Returns true if the field is virtual.""" 390*99e0aae7SDavid Rees # TODO(bolms): Should there be a more explicit indicator that a field is 391*99e0aae7SDavid Rees # virtual? 392*99e0aae7SDavid Rees return not field_ir.HasField("location") 393*99e0aae7SDavid Rees 394*99e0aae7SDavid Rees 395*99e0aae7SDavid Reesdef field_is_read_only(field_ir): 396*99e0aae7SDavid Rees """Returns true if the field is read-only.""" 397*99e0aae7SDavid Rees # For now, all virtual fields are read-only, and no non-virtual fields are 398*99e0aae7SDavid Rees # read-only. 399*99e0aae7SDavid Rees return ir_data_utils.reader(field_ir).write_method.read_only 400