Generate value type constraints.
Add an Opcode::constraints() method which returns an OpcodeConstraints object. This object provides information on instruction polymorphism and how many results is produced. Generate a list of TypeSet objects for checking free type variables. The type sets are parametrized rather than being represented as fully general sets. Add UniqueTable and UniqueSeqTable classes to the meta code generator. Use for compressing tabular data by removing duplicates.
This commit is contained in:
@@ -4,6 +4,7 @@ Generate sources with instruction info.
|
||||
|
||||
import srcgen
|
||||
import constant_hash
|
||||
from unique_table import UniqueTable, UniqueSeqTable
|
||||
import cretonne
|
||||
|
||||
|
||||
@@ -97,7 +98,8 @@ def gen_instruction_data_impl(fmt):
|
||||
|
||||
fmt.doc_comment('Mutable reference to second result value, if any.')
|
||||
with fmt.indented(
|
||||
"pub fn second_result_mut<'a>(&'a mut self) -> Option<&'a mut Value> {", '}'):
|
||||
"pub fn second_result_mut<'a>(&'a mut self)" +
|
||||
" -> Option<&'a mut Value> {", '}'):
|
||||
with fmt.indented('match *self {', '}'):
|
||||
for f in cretonne.InstructionFormat.all_formats:
|
||||
if not f.multiple_results:
|
||||
@@ -131,7 +133,11 @@ def collect_instr_groups(targets):
|
||||
|
||||
|
||||
def gen_opcodes(groups, fmt):
|
||||
"""Generate opcode enumerations."""
|
||||
"""
|
||||
Generate opcode enumerations.
|
||||
|
||||
Return a list of all instructions.
|
||||
"""
|
||||
|
||||
fmt.doc_comment('An instruction opcode.')
|
||||
fmt.doc_comment('')
|
||||
@@ -193,6 +199,125 @@ def gen_opcodes(groups, fmt):
|
||||
else:
|
||||
fmt.format('Opcode::{},', i.camel_name)
|
||||
fmt.line()
|
||||
return instrs
|
||||
|
||||
|
||||
def get_constraint(op, ctrl_typevar, type_sets):
|
||||
"""
|
||||
Get the value type constraint for an SSA value operand, where
|
||||
`ctrl_typevar` is the controlling type variable.
|
||||
|
||||
Each operand constraint is represented as a string, one of:
|
||||
|
||||
- `Concrete(vt)`, where `vt` is a value type name.
|
||||
- `Free(idx)` where `idx` is an index into `type_sets`.
|
||||
- `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints.
|
||||
"""
|
||||
t = op.typ
|
||||
assert t.operand_kind() is cretonne.value
|
||||
|
||||
# A concrete value type.
|
||||
if isinstance(t, cretonne.ValueType):
|
||||
return 'Concrete({})'.format(t.rust_name())
|
||||
|
||||
if t.free_typevar() is not ctrl_typevar:
|
||||
assert not t.is_derived
|
||||
return 'Free({})'.format(type_sets.add(t.type_set))
|
||||
|
||||
if t.is_derived:
|
||||
assert t.base is ctrl_typevar, "Not derived directly from ctrl_typevar"
|
||||
return t.derived_func
|
||||
|
||||
assert t is ctrl_typevar
|
||||
return 'Same'
|
||||
|
||||
|
||||
def gen_type_constraints(fmt, instrs):
|
||||
"""
|
||||
Generate value type constraints for all instructions.
|
||||
|
||||
- Emit a compact constant table of ValueTypeSet objects.
|
||||
- Emit a compact constant table of OperandConstraint objects.
|
||||
- Emit an opcode-indexed table of instruction constraints.
|
||||
|
||||
"""
|
||||
|
||||
# Table of TypeSet instances.
|
||||
type_sets = UniqueTable()
|
||||
|
||||
# Table of operand constraint sequences (as tuples). Each operand
|
||||
# constraint is represented as a string, one of:
|
||||
# - `Concrete(vt)`, where `vt` is a value type name.
|
||||
# - `Free(idx)` where `idx` isan index into `type_sets`.
|
||||
# - `Same`, `Lane`, `AsBool` for controlling typevar-derived constraints.
|
||||
operand_seqs = UniqueSeqTable()
|
||||
|
||||
# Preload table with constraints for typical binops.
|
||||
operand_seqs.add(['Same'] * 3)
|
||||
|
||||
# TypeSet indexes are encoded in 3 bits, with `111` reserved.
|
||||
typeset_limit = 7
|
||||
|
||||
fmt.comment('Table of opcode constraints.')
|
||||
with fmt.indented(
|
||||
'const OPCODE_CONSTRAINTS : [OpcodeConstraints; {}] = ['
|
||||
.format(len(instrs)), '];'):
|
||||
for i in instrs:
|
||||
# Collect constraints for the value results, not including
|
||||
# `variable_args` results which are always special cased.
|
||||
constraints = list()
|
||||
ctrl_typevar = None
|
||||
ctrl_typeset = typeset_limit
|
||||
if i.is_polymorphic:
|
||||
ctrl_typevar = i.ctrl_typevar
|
||||
ctrl_typeset = type_sets.add(ctrl_typevar.type_set)
|
||||
for idx in i.value_results:
|
||||
constraints.append(
|
||||
get_constraint(i.outs[idx], ctrl_typevar, type_sets))
|
||||
for idx in i.format.value_operands:
|
||||
constraints.append(
|
||||
get_constraint(i.ins[idx], ctrl_typevar, type_sets))
|
||||
offset = operand_seqs.add(constraints)
|
||||
fixed_results = len(i.value_results)
|
||||
use_typevar_operand = i.is_polymorphic and i.use_typevar_operand
|
||||
fmt.comment(
|
||||
'{}: fixed_results={}, use_typevar_operand={}'
|
||||
.format(i.camel_name, fixed_results, use_typevar_operand))
|
||||
fmt.comment('Constraints={}'.format(constraints))
|
||||
if i.is_polymorphic:
|
||||
fmt.comment(
|
||||
'Polymorphic over {}'.format(ctrl_typevar.type_set))
|
||||
# Compute the bit field encoding, c.f. instructions.rs.
|
||||
assert fixed_results < 8, "Bit field encoding too tight"
|
||||
bits = (offset << 8) | (ctrl_typeset << 4) | fixed_results
|
||||
if use_typevar_operand:
|
||||
bits |= 8
|
||||
assert bits < 0x10000, "Constraint table too large for bit field"
|
||||
fmt.line('OpcodeConstraints({:#06x}),'.format(bits))
|
||||
|
||||
fmt.comment('Table of value type sets.')
|
||||
assert len(type_sets.table) <= typeset_limit, "Too many type sets"
|
||||
with fmt.indented(
|
||||
'const TYPE_SETS : [ValueTypeSet; {}] = ['
|
||||
.format(len(type_sets.table)), '];'):
|
||||
for ts in type_sets.table:
|
||||
with fmt.indented('ValueTypeSet {', '},'):
|
||||
if ts.base:
|
||||
fmt.line('base: {},'.format(ts.base.rust_name()))
|
||||
else:
|
||||
fmt.line('base: types::VOID,')
|
||||
for field in ts._fields:
|
||||
if field == 'base':
|
||||
continue
|
||||
fmt.line('{}: {},'.format(
|
||||
field, str(getattr(ts, field)).lower()))
|
||||
|
||||
fmt.comment('Table of operand constraint sequences.')
|
||||
with fmt.indented(
|
||||
'const OPERAND_CONSTRAINTS : [OperandConstraint; {}] = ['
|
||||
.format(len(operand_seqs.table)), '];'):
|
||||
for c in operand_seqs.table:
|
||||
fmt.line('OperandConstraint::{},'.format(c))
|
||||
|
||||
|
||||
def generate(targets, out_dir):
|
||||
@@ -202,5 +327,6 @@ def generate(targets, out_dir):
|
||||
fmt = srcgen.Formatter()
|
||||
gen_formats(fmt)
|
||||
gen_instruction_data_impl(fmt)
|
||||
gen_opcodes(groups, fmt)
|
||||
instrs = gen_opcodes(groups, fmt)
|
||||
gen_type_constraints(fmt, instrs)
|
||||
fmt.update_file('opcodes.rs', out_dir)
|
||||
|
||||
Reference in New Issue
Block a user