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 2f50ae3166
commit 63a6ade0a5
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.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
# `has_value_list` is set.
self.num_value_operands = 0
# Does this format use a value list for storing value operands?
self.has_value_list = False
# Operand kinds for the immediate operands.
self.imm_kinds = tuple(self._process_member_names(kinds))
# Operand fields for the immediate operands. All other instruction
# 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.
self.typevar_operand = kwargs.get('typevar_operand', None) # type: int
@@ -82,9 +80,9 @@ class InstructionFormat(object):
self.typevar_operand = 0
# Compute a signature for the global registry.
imm_kinds = tuple(f.kind for f in self.imm_fields)
sig = (
self.multiple_results, self.imm_kinds,
self.num_value_operands,
self.multiple_results, imm_kinds, self.num_value_operands,
self.has_value_list)
if sig in InstructionFormat._registry:
raise RuntimeError(
@@ -94,7 +92,7 @@ class InstructionFormat(object):
InstructionFormat.all_formats.append(self)
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.
@@ -102,10 +100,11 @@ class InstructionFormat(object):
pair. The member names correspond to members in the Rust
`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:
if isinstance(arg, OperandKind):
member = arg.default_member
@@ -119,13 +118,13 @@ class InstructionFormat(object):
elif k is VARIABLE_ARGS:
self.has_value_list = True
else:
self.imm_members.append(member)
yield k
yield FormatField(self, inum, k, member)
inum += 1
def __str__(self):
# type: () -> str
args = ', '.join('{}: {}'.format(m, k)
for m, k in zip(self.imm_members, self.imm_kinds))
args = ', '.join(
'{}: {}'.format(f.member, f.kind) for f in self.imm_fields)
return '{}(imms=({}), vals={})'.format(
self.name, args, self.num_value_operands)
@@ -137,16 +136,16 @@ class InstructionFormat(object):
Each non-value format member becomes a corresponding `FormatField`
attribute.
"""
try:
i = self.imm_members.index(attr)
except ValueError:
for f in self.imm_fields:
if f.member == attr:
# Cache this field attribute so we won't have to search again.
setattr(self, attr, f)
return f
raise AttributeError(
'{} is neither a {} member or a '
.format(attr, self.name) +
'normal InstructionFormat attribute')
field = FormatField(self, i, attr)
setattr(self, attr, field)
return field
@staticmethod
def lookup(ins, outs):
@@ -207,26 +206,28 @@ class InstructionFormat(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`
data type.
:param format: Parent `InstructionFormat`.
:param operand: Immediate operand number in parent.
:param name: Member name in `InstructionData` variant.
:param iformat: Parent `InstructionFormat`.
:param immnum: Immediate operand number in parent.
:param kind: Immediate Operand kind.
:param member: Member name in `InstructionData` variant.
"""
def __init__(self, format, operand, name):
# type: (InstructionFormat, int, str) -> None
self.format = format
self.operand = operand
self.name = name
def __init__(self, iform, immnum, kind, member):
# type: (InstructionFormat, int, OperandKind, str) -> None
self.format = iform
self.immnum = immnum
self.kind = kind
self.member = member
def __str__(self):
# type: () -> str
return '{}.{}'.format(self.format.name, self.name)
return '{}.{}'.format(self.format.name, self.member)
def rust_name(self):
# type: () -> str
return self.name
return self.member

View File

@@ -207,7 +207,7 @@ class FieldPredicate(object):
def __str__(self):
# 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))
def predicate_context(self):

View File

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

View File

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

View File

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