xref: /aosp_15_r20/external/emboss/compiler/util/ir_util.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"""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