From 89ff979d75306cff5aa4e55ba0777d3cc58f3af3 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 31 Mar 2017 10:12:37 -0700 Subject: [PATCH] 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. --- lib/cretonne/meta/cdsl/formats.py | 73 ++++++++++++++-------------- lib/cretonne/meta/cdsl/predicates.py | 2 +- lib/cretonne/meta/gen_encoding.py | 2 +- lib/cretonne/meta/gen_instr.py | 8 +-- lib/cretonne/meta/gen_legalizer.py | 6 +-- 5 files changed, 46 insertions(+), 45 deletions(-) diff --git a/lib/cretonne/meta/cdsl/formats.py b/lib/cretonne/meta/cdsl/formats.py index 9549eac1e0..f08d6fa119 100644 --- a/lib/cretonne/meta/cdsl/formats.py +++ b/lib/cretonne/meta/cdsl/formats.py @@ -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: - 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 + 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') @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 diff --git a/lib/cretonne/meta/cdsl/predicates.py b/lib/cretonne/meta/cdsl/predicates.py index e75920d948..273f8be9a1 100644 --- a/lib/cretonne/meta/cdsl/predicates.py +++ b/lib/cretonne/meta/cdsl/predicates.py @@ -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): diff --git a/lib/cretonne/meta/gen_encoding.py b/lib/cretonne/meta/gen_encoding.py index e78d8942dc..e4faa6410c 100644 --- a/lib/cretonne/meta/gen_encoding.py +++ b/lib/cretonne/meta/gen_encoding.py @@ -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), '}'): diff --git a/lib/cretonne/meta/gen_instr.py b/lib/cretonne/meta/gen_instr.py index dc5257ffef..9ce279dc52 100644 --- a/lib/cretonne/meta/gen_instr.py +++ b/lib/cretonne/meta/gen_instr.py @@ -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: diff --git a/lib/cretonne/meta/gen_legalizer.py b/lib/cretonne/meta/gen_legalizer.py index 93f2bc857c..7beda84771 100644 --- a/lib/cretonne/meta/gen_legalizer.py +++ b/lib/cretonne/meta/gen_legalizer.py @@ -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'