Expand OpcodeConstraints to 32 bits.
Make room for 255 different type sets and 2^16 entries in the operand constraints table.
This commit is contained in:
@@ -398,52 +398,49 @@ pub enum BranchInfo<'a> {
|
|||||||
/// The `InstructionFormat` determines the constraints on most operands, but `Value` operands and
|
/// The `InstructionFormat` determines the constraints on most operands, but `Value` operands and
|
||||||
/// results are not determined by the format. Every `Opcode` has an associated
|
/// results are not determined by the format. Every `Opcode` has an associated
|
||||||
/// `OpcodeConstraints` object that provides the missing details.
|
/// `OpcodeConstraints` object that provides the missing details.
|
||||||
///
|
|
||||||
/// Since there can be a lot of opcodes, the `OpcodeConstraints` object is encoded as a bit field
|
|
||||||
/// by the `meta/gen_instr.py` script.
|
|
||||||
///
|
|
||||||
/// The bit field bits are:
|
|
||||||
///
|
|
||||||
/// Bits 0-2:
|
|
||||||
/// Number of fixed result values. This does not include `variable_args` results as are
|
|
||||||
/// produced by call instructions.
|
|
||||||
///
|
|
||||||
/// Bit 3:
|
|
||||||
/// This opcode is polymorphic and the controlling type variable can be inferred from the
|
|
||||||
/// designated input operand. This is the `typevar_operand` index given to the
|
|
||||||
/// `InstructionFormat` meta language object. When bit 0 is not set, the controlling type
|
|
||||||
/// variable must be the first output value instead.
|
|
||||||
///
|
|
||||||
/// Bits 4-7:
|
|
||||||
/// Permitted set of types for the controlling type variable as an index into `TYPE_SETS`.
|
|
||||||
///
|
|
||||||
/// Bits 8-15:
|
|
||||||
/// Offset into `OPERAND_CONSTRAINT` table of the descriptors for this opcode. The first
|
|
||||||
/// `fixed_results()` entries describe the result constraints, then follows constraints for the
|
|
||||||
/// fixed `Value` input operands. The number of `Value` inputs isdetermined by the instruction
|
|
||||||
/// format.
|
|
||||||
///
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct OpcodeConstraints(u16);
|
pub struct OpcodeConstraints {
|
||||||
|
/// Flags for this opcode encoded as a bit field:
|
||||||
|
///
|
||||||
|
/// Bits 0-2:
|
||||||
|
/// Number of fixed result values. This does not include `variable_args` results as are
|
||||||
|
/// produced by call instructions.
|
||||||
|
///
|
||||||
|
/// Bit 3:
|
||||||
|
/// This opcode is polymorphic and the controlling type variable can be inferred from the
|
||||||
|
/// designated input operand. This is the `typevar_operand` index given to the
|
||||||
|
/// `InstructionFormat` meta language object. When bit 0 is not set, the controlling type
|
||||||
|
/// variable must be the first output value instead.
|
||||||
|
flags: u8,
|
||||||
|
|
||||||
|
/// Permitted set of types for the controlling type variable as an index into `TYPE_SETS`.
|
||||||
|
typeset_offset: u8,
|
||||||
|
|
||||||
|
/// Offset into `OPERAND_CONSTRAINT` table of the descriptors for this opcode. The first
|
||||||
|
/// `fixed_results()` entries describe the result constraints, then follows constraints for the
|
||||||
|
/// fixed `Value` input operands. The number of `Value` inputs is determined by the instruction
|
||||||
|
/// format.
|
||||||
|
constraint_offset: u16,
|
||||||
|
}
|
||||||
|
|
||||||
impl OpcodeConstraints {
|
impl OpcodeConstraints {
|
||||||
/// Can the controlling type variable for this opcode be inferred from the designated value
|
/// Can the controlling type variable for this opcode be inferred from the designated value
|
||||||
/// input operand?
|
/// input operand?
|
||||||
/// This also implies that this opcode is polymorphic.
|
/// This also implies that this opcode is polymorphic.
|
||||||
pub fn use_typevar_operand(self) -> bool {
|
pub fn use_typevar_operand(self) -> bool {
|
||||||
(self.0 & 0x8) != 0
|
(self.flags & 0x8) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the number of *fixed* result values produced by this opcode.
|
/// Get the number of *fixed* result values produced by this opcode.
|
||||||
/// This does not include `variable_args` produced by calls.
|
/// This does not include `variable_args` produced by calls.
|
||||||
pub fn fixed_results(self) -> usize {
|
pub fn fixed_results(self) -> usize {
|
||||||
(self.0 & 0x7) as usize
|
(self.flags & 0x7) as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the offset into `TYPE_SETS` for the controlling type variable.
|
/// Get the offset into `TYPE_SETS` for the controlling type variable.
|
||||||
/// Returns `None` if the instruction is not polymorphic.
|
/// Returns `None` if the instruction is not polymorphic.
|
||||||
fn typeset_offset(self) -> Option<usize> {
|
fn typeset_offset(self) -> Option<usize> {
|
||||||
let offset = ((self.0 & 0xff) >> 4) as usize;
|
let offset = self.typeset_offset as usize;
|
||||||
if offset < TYPE_SETS.len() {
|
if offset < TYPE_SETS.len() {
|
||||||
Some(offset)
|
Some(offset)
|
||||||
} else {
|
} else {
|
||||||
@@ -453,7 +450,7 @@ impl OpcodeConstraints {
|
|||||||
|
|
||||||
/// Get the offset into OPERAND_CONSTRAINTS where the descriptors for this opcode begin.
|
/// Get the offset into OPERAND_CONSTRAINTS where the descriptors for this opcode begin.
|
||||||
fn constraint_offset(self) -> usize {
|
fn constraint_offset(self) -> usize {
|
||||||
(self.0 >> 8) as usize
|
self.constraint_offset as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the value type of result number `n`, having resolved the controlling type variable to
|
/// Get the value type of result number `n`, having resolved the controlling type variable to
|
||||||
|
|||||||
@@ -297,8 +297,8 @@ def gen_type_constraints(fmt, instrs):
|
|||||||
# Preload table with constraints for typical binops.
|
# Preload table with constraints for typical binops.
|
||||||
operand_seqs.add(['Same'] * 3)
|
operand_seqs.add(['Same'] * 3)
|
||||||
|
|
||||||
# TypeSet indexes are encoded in 3 bits, with `111` reserved.
|
# TypeSet indexes are encoded in 8 bits, with `0xff` reserved.
|
||||||
typeset_limit = 7
|
typeset_limit = 0xff
|
||||||
|
|
||||||
fmt.comment('Table of opcode constraints.')
|
fmt.comment('Table of opcode constraints.')
|
||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
@@ -331,11 +331,14 @@ def gen_type_constraints(fmt, instrs):
|
|||||||
'Polymorphic over {}'.format(ctrl_typevar.type_set))
|
'Polymorphic over {}'.format(ctrl_typevar.type_set))
|
||||||
# Compute the bit field encoding, c.f. instructions.rs.
|
# Compute the bit field encoding, c.f. instructions.rs.
|
||||||
assert fixed_results < 8, "Bit field encoding too tight"
|
assert fixed_results < 8, "Bit field encoding too tight"
|
||||||
bits = (offset << 8) | (ctrl_typeset << 4) | fixed_results
|
flags = fixed_results
|
||||||
if use_typevar_operand:
|
if use_typevar_operand:
|
||||||
bits |= 8
|
flags |= 8
|
||||||
assert bits < 0x10000, "Constraint table too large for bit field"
|
|
||||||
fmt.line('OpcodeConstraints({:#06x}),'.format(bits))
|
with fmt.indented('OpcodeConstraints {', '},'):
|
||||||
|
fmt.line('flags: {:#04x},'.format(flags))
|
||||||
|
fmt.line('typeset_offset: {},'.format(ctrl_typeset))
|
||||||
|
fmt.line('constraint_offset: {},'.format(offset))
|
||||||
|
|
||||||
fmt.comment('Table of value type sets.')
|
fmt.comment('Table of value type sets.')
|
||||||
assert len(type_sets.table) <= typeset_limit, "Too many type sets"
|
assert len(type_sets.table) <= typeset_limit, "Too many type sets"
|
||||||
|
|||||||
Reference in New Issue
Block a user