Add InstructionFormat.imm_fields.

Consolidate the imm_members and imm_kinds into this list so the
FormatField is the single definition of these properties.

This makes it easier to access the precomputed FormatFields
parametrically, avoiding going through getattr().

This is better for type checking too.
This commit is contained in:
Jakob Stoklund Olesen
2017-03-31 10:12:37 -07:00
parent b31ca83b91
commit 89ff979d75
5 changed files with 46 additions and 45 deletions

View File

@@ -59,17 +59,15 @@ class InstructionFormat(object):
self.name = kwargs.get('name', None) # type: str self.name = kwargs.get('name', None) # type: str
self.multiple_results = kwargs.get('multiple_results', False) self.multiple_results = kwargs.get('multiple_results', False)
# Struct member names for the immediate operands. All other instruction
# operands are values or variable argument lists. They are all handled
# specially.
self.imm_members = list() # type: List[str]
# The number of value operands stored in the format, or `None` when # The number of value operands stored in the format, or `None` when
# `has_value_list` is set. # `has_value_list` is set.
self.num_value_operands = 0 self.num_value_operands = 0
# Does this format use a value list for storing value operands? # Does this format use a value list for storing value operands?
self.has_value_list = False self.has_value_list = False
# Operand kinds for the immediate operands. # Operand fields for the immediate operands. All other instruction
self.imm_kinds = tuple(self._process_member_names(kinds)) # operands are values or variable argument lists. They are all handled
# specially.
self.imm_fields = tuple(self._process_member_names(kinds))
# The typevar_operand argument must point to a 'value' operand. # The typevar_operand argument must point to a 'value' operand.
self.typevar_operand = kwargs.get('typevar_operand', None) # type: int self.typevar_operand = kwargs.get('typevar_operand', None) # type: int
@@ -82,9 +80,9 @@ class InstructionFormat(object):
self.typevar_operand = 0 self.typevar_operand = 0
# Compute a signature for the global registry. # Compute a signature for the global registry.
imm_kinds = tuple(f.kind for f in self.imm_fields)
sig = ( sig = (
self.multiple_results, self.imm_kinds, self.multiple_results, imm_kinds, self.num_value_operands,
self.num_value_operands,
self.has_value_list) self.has_value_list)
if sig in InstructionFormat._registry: if sig in InstructionFormat._registry:
raise RuntimeError( raise RuntimeError(
@@ -94,7 +92,7 @@ class InstructionFormat(object):
InstructionFormat.all_formats.append(self) InstructionFormat.all_formats.append(self)
def _process_member_names(self, kinds): def _process_member_names(self, kinds):
# type: (Sequence[Union[OperandKind, Tuple[str, OperandKind]]]) -> Iterable[OperandKind] # noqa # type: (Sequence[Union[OperandKind, Tuple[str, OperandKind]]]) -> Iterable[FormatField] # noqa
""" """
Extract names of all the immediate operands in the kinds tuple. Extract names of all the immediate operands in the kinds tuple.
@@ -102,10 +100,11 @@ class InstructionFormat(object):
pair. The member names correspond to members in the Rust pair. The member names correspond to members in the Rust
`InstructionData` data structure. `InstructionData` data structure.
Update the fields `num_value_operands` and `imm_members`. Updates the fields `self.num_value_operands` and `self.has_value_list`.
Yields the immediate operand kinds. Yields the immediate operand fields.
""" """
inum = 0
for arg in kinds: for arg in kinds:
if isinstance(arg, OperandKind): if isinstance(arg, OperandKind):
member = arg.default_member member = arg.default_member
@@ -119,13 +118,13 @@ class InstructionFormat(object):
elif k is VARIABLE_ARGS: elif k is VARIABLE_ARGS:
self.has_value_list = True self.has_value_list = True
else: else:
self.imm_members.append(member) yield FormatField(self, inum, k, member)
yield k inum += 1
def __str__(self): def __str__(self):
# type: () -> str # type: () -> str
args = ', '.join('{}: {}'.format(m, k) args = ', '.join(
for m, k in zip(self.imm_members, self.imm_kinds)) '{}: {}'.format(f.member, f.kind) for f in self.imm_fields)
return '{}(imms=({}), vals={})'.format( return '{}(imms=({}), vals={})'.format(
self.name, args, self.num_value_operands) self.name, args, self.num_value_operands)
@@ -137,16 +136,16 @@ class InstructionFormat(object):
Each non-value format member becomes a corresponding `FormatField` Each non-value format member becomes a corresponding `FormatField`
attribute. attribute.
""" """
try: for f in self.imm_fields:
i = self.imm_members.index(attr) if f.member == attr:
except ValueError: # Cache this field attribute so we won't have to search again.
raise AttributeError( setattr(self, attr, f)
'{} is neither a {} member or a ' return f
.format(attr, self.name) +
'normal InstructionFormat attribute') raise AttributeError(
field = FormatField(self, i, attr) '{} is neither a {} member or a '
setattr(self, attr, field) .format(attr, self.name) +
return field 'normal InstructionFormat attribute')
@staticmethod @staticmethod
def lookup(ins, outs): def lookup(ins, outs):
@@ -207,26 +206,28 @@ class InstructionFormat(object):
class FormatField(object): class FormatField(object):
""" """
A field in an instruction format. An immediate field in an instruction format.
This corresponds to a single member of a variant of the `InstructionData` This corresponds to a single member of a variant of the `InstructionData`
data type. data type.
:param format: Parent `InstructionFormat`. :param iformat: Parent `InstructionFormat`.
:param operand: Immediate operand number in parent. :param immnum: Immediate operand number in parent.
:param name: Member name in `InstructionData` variant. :param kind: Immediate Operand kind.
:param member: Member name in `InstructionData` variant.
""" """
def __init__(self, format, operand, name): def __init__(self, iform, immnum, kind, member):
# type: (InstructionFormat, int, str) -> None # type: (InstructionFormat, int, OperandKind, str) -> None
self.format = format self.format = iform
self.operand = operand self.immnum = immnum
self.name = name self.kind = kind
self.member = member
def __str__(self): def __str__(self):
# type: () -> str # type: () -> str
return '{}.{}'.format(self.format.name, self.name) return '{}.{}'.format(self.format.name, self.member)
def rust_name(self): def rust_name(self):
# type: () -> str # type: () -> str
return self.name return self.member

View File

@@ -207,7 +207,7 @@ class FieldPredicate(object):
def __str__(self): def __str__(self):
# type: () -> str # type: () -> str
args = (self.field.name,) + tuple(map(str, self.args)) args = (self.field.rust_name(),) + tuple(map(str, self.args))
return '{}({})'.format(self.function, ', '.join(args)) return '{}({})'.format(self.function, ', '.join(args))
def predicate_context(self): def predicate_context(self):

View File

@@ -90,7 +90,7 @@ def emit_instp(instp, fmt):
fnames = set() # type: Set[str] fnames = set() # type: Set[str]
for p in leafs: for p in leafs:
assert isinstance(p, FieldPredicate) assert isinstance(p, FieldPredicate)
fnames.add(p.field.name) fnames.add(p.field.rust_name())
fields = ', '.join(sorted(fnames)) fields = ', '.join(sorted(fnames))
with fmt.indented('{} => {{'.format(instp.number), '}'): with fmt.indented('{} => {{'.format(instp.number), '}'):

View File

@@ -515,8 +515,8 @@ def gen_format_constructor(iform, fmt):
result_type = 'result_type' result_type = 'result_type'
# Normal operand arguments. Start with the immediate operands. # Normal operand arguments. Start with the immediate operands.
for kind, name in zip(iform.imm_kinds, iform.imm_members): for f in iform.imm_fields:
args.append('{}: {}'.format(name, kind.rust_type)) args.append('{}: {}'.format(f.member, f.kind.rust_type))
# Then the value operands. # Then the value operands.
if iform.has_value_list: if iform.has_value_list:
# Take all value arguments as a finished value list. The value lists # Take all value arguments as a finished value list. The value lists
@@ -557,8 +557,8 @@ def gen_member_inits(iform, fmt):
# Immediate operands. # Immediate operands.
# We have local variables with the same names as the members. # We have local variables with the same names as the members.
for member in iform.imm_members: for f in iform.imm_fields:
fmt.line('{}: {},'.format(member, member)) fmt.line('{}: {},'.format(f.member, f.member))
# Value operands. # Value operands.
if iform.has_value_list: if iform.has_value_list:

View File

@@ -43,8 +43,8 @@ def unwrap_inst(iref, node, fmt):
'let ({}) = if let InstructionData::{} {{' 'let ({}) = if let InstructionData::{} {{'
.format(', '.join(map(str, expr.args)), iform.name), '};'): .format(', '.join(map(str, expr.args)), iform.name), '};'):
# Fields are encoded directly. # Fields are encoded directly.
for m in iform.imm_members: for f in iform.imm_fields:
fmt.line('{},'.format(m)) fmt.line('{},'.format(f.member))
if nvops == 1: if nvops == 1:
fmt.line('arg,') fmt.line('arg,')
elif iform.has_value_list or nvops > 1: elif iform.has_value_list or nvops > 1:
@@ -58,7 +58,7 @@ def unwrap_inst(iref, node, fmt):
for opnum, op in enumerate(expr.inst.ins): for opnum, op in enumerate(expr.inst.ins):
if op.is_immediate(): if op.is_immediate():
n = expr.inst.imm_opnums.index(opnum) n = expr.inst.imm_opnums.index(opnum)
outs.append(iform.imm_members[n]) outs.append(iform.imm_fields[n].member)
elif op.is_value(): elif op.is_value():
if nvops == 1: if nvops == 1:
arg = 'arg' arg = 'arg'