Python InstructionFormat refactoring.

Make some changes that will make it easier to get rid of the
'value_operands' and 'members' fields in the Python InstructionFormat
class. This is necessary to be able to combine instruction formats that
all use a value list representation, but with different fixed value
operands. The goal is to eventually identify formats by a new signature:

   (multiple_results, imm_kinds, num_value_operands)

Start by adding new fields:

- imm_members and imm_kinds are lists describing the format operands,
  excluding any values and variable_args operands.
- num_value_operands is the number of fixed value operands, or None in a
  has_value-list format.

Use these new members in preference to the old ones where possible.
This commit is contained in:
Jakob Stoklund Olesen
2017-03-09 21:03:52 -08:00
parent ec5ee70a5c
commit f3d7485494
3 changed files with 31 additions and 30 deletions

View File

@@ -57,16 +57,23 @@ class InstructionFormat(object):
self.has_value_list = kwargs.get('value_list', False) self.has_value_list = kwargs.get('value_list', False)
self.boxed_storage = kwargs.get('boxed_storage', False) self.boxed_storage = kwargs.get('boxed_storage', False)
self.members = list() # type: List[str] self.members = list() # type: List[str]
# 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]
# Operand kinds for the immediate operands.
self.imm_kinds = list() # type: List[OperandKind]
# The number of value operands stored in the format, or `None` when
# `has_value_list` is set.
self.num_value_operands = 0
self.kinds = tuple(self._process_member_names(kinds)) self.kinds = tuple(self._process_member_names(kinds))
# Which of self.kinds are `value`? # Which of self.kinds are `value`?
self.value_operands = tuple( self.value_operands = tuple(
i for i, k in enumerate(self.kinds) if k is VALUE) i for i, k in enumerate(self.kinds) if k is VALUE)
# We require a value list for storage of variable arguments.
if VARIABLE_ARGS in self.kinds:
assert self.has_value_list, "Need a value list for variable args"
# 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
if self.typevar_operand is not None: if self.typevar_operand is not None:
@@ -102,6 +109,17 @@ class InstructionFormat(object):
k = arg k = arg
else: else:
member, k = arg member, k = arg
# We define 'immediate' as not a value or variable arguments.
if k is VALUE:
self.num_value_operands += 1
elif k is VARIABLE_ARGS:
# We require a value list for storage of variable arguments.
assert self.has_value_list, "Need a value list"
else:
self.imm_kinds.append(k)
self.imm_members.append(member)
self.members.append(member) self.members.append(member)
yield k yield k

View File

@@ -84,20 +84,11 @@ def gen_arguments_method(fmt, is_mut):
.format(n, mut, mut, as_slice)) .format(n, mut, mut, as_slice))
continue continue
has_varargs = cdsl.operands.VARIABLE_ARGS in f.kinds
# Formats with both fixed and variable arguments delegate to
# the data struct. We need to work around borrow checker quirks
# when extracting two mutable references.
if has_varargs and len(f.value_operands) > 0:
fmt.line(
'{} {{ ref {}data, .. }} => data.{}(),'
.format(n, mut, method))
continue
# Fixed args. # Fixed args.
if len(f.value_operands) == 0: if f.num_value_operands == 0:
arg = '&{}[]'.format(mut) arg = '&{}[]'.format(mut)
capture = '' capture = ''
elif len(f.value_operands) == 1: elif f.num_value_operands == 1:
if f.boxed_storage: if f.boxed_storage:
capture = 'ref {}data, '.format(mut) capture = 'ref {}data, '.format(mut)
arg = '{}(&{}data.arg)'.format(rslice, mut) arg = '{}(&{}data.arg)'.format(rslice, mut)
@@ -111,16 +102,9 @@ def gen_arguments_method(fmt, is_mut):
else: else:
capture = 'ref {}args, '.format(mut) capture = 'ref {}args, '.format(mut)
arg = 'args' arg = 'args'
# Varargs.
if cdsl.operands.VARIABLE_ARGS in f.kinds:
varg = '&{}data.varargs'.format(mut)
capture = 'ref {}data, '.format(mut)
else:
varg = '&{}[]'.format(mut)
fmt.line( fmt.line(
'{} {{ {} .. }} => [{}, {}],' '{} {{ {} .. }} => [{}, &{}[]],'
.format(n, capture, arg, varg)) .format(n, capture, arg, mut))
def gen_instruction_data_impl(fmt): def gen_instruction_data_impl(fmt):
@@ -219,7 +203,7 @@ def gen_instruction_data_impl(fmt):
fmt.line( fmt.line(
'{} {{ ref args, .. }} => ' '{} {{ ref args, .. }} => '
'args.get({}, pool),'.format(n, i)) 'args.get({}, pool),'.format(n, i))
elif len(f.value_operands) == 1: elif f.num_value_operands == 1:
# We have a single value operand called 'arg'. # We have a single value operand called 'arg'.
if f.boxed_storage: if f.boxed_storage:
fmt.line( fmt.line(
@@ -564,9 +548,9 @@ def gen_member_inits(iform, fmt):
if iform.has_value_list: if iform.has_value_list:
# Value-list formats put *all* arguments in the list. # Value-list formats put *all* arguments in the list.
fmt.line('args: vlist,') fmt.line('args: vlist,')
elif len(iform.value_operands) == 1: elif iform.num_value_operands == 1:
fmt.line('arg: op{},'.format(iform.value_operands[0])) fmt.line('arg: op{},'.format(iform.value_operands[0]))
elif len(iform.value_operands) > 1: elif iform.num_value_operands > 1:
fmt.line('args: [{}],'.format( fmt.line('args: [{}],'.format(
', '.join('op{}'.format(i) for i in iform.value_operands))) ', '.join('op{}'.format(i) for i in iform.value_operands)))

View File

@@ -46,9 +46,8 @@ def unwrap_inst(iref, node, fmt):
fmt.line('ref data,') fmt.line('ref data,')
else: else:
# Fields are encoded directly. # Fields are encoded directly.
for m in iform.members: for m in iform.imm_members:
if m: fmt.line('{},'.format(m))
fmt.line('{},'.format(m))
if nvops == 1: if nvops == 1:
fmt.line('arg,') fmt.line('arg,')
elif nvops > 1: elif nvops > 1: