From 2a2871e739d98378234f6b223fbde0595600c5f1 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Tue, 27 Sep 2016 16:09:26 -0700 Subject: [PATCH] Expand OpcodeConstraints to 32 bits. Make room for 255 different type sets and 2^16 entries in the operand constraints table. --- meta/gen_instr.py | 15 ++++---- src/libcretonne/ir/instructions.rs | 57 ++++++++++++++---------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/meta/gen_instr.py b/meta/gen_instr.py index cc636cf83a..582c0477f0 100644 --- a/meta/gen_instr.py +++ b/meta/gen_instr.py @@ -297,8 +297,8 @@ def gen_type_constraints(fmt, instrs): # 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 + # TypeSet indexes are encoded in 8 bits, with `0xff` reserved. + typeset_limit = 0xff fmt.comment('Table of opcode constraints.') with fmt.indented( @@ -331,11 +331,14 @@ def gen_type_constraints(fmt, instrs): '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 + flags = fixed_results if use_typevar_operand: - bits |= 8 - assert bits < 0x10000, "Constraint table too large for bit field" - fmt.line('OpcodeConstraints({:#06x}),'.format(bits)) + flags |= 8 + + 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.') assert len(type_sets.table) <= typeset_limit, "Too many type sets" diff --git a/src/libcretonne/ir/instructions.rs b/src/libcretonne/ir/instructions.rs index f60d23c60c..9e259273cc 100644 --- a/src/libcretonne/ir/instructions.rs +++ b/src/libcretonne/ir/instructions.rs @@ -398,52 +398,49 @@ pub enum BranchInfo<'a> { /// The `InstructionFormat` determines the constraints on most operands, but `Value` operands and /// results are not determined by the format. Every `Opcode` has an associated /// `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)] -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 { /// Can the controlling type variable for this opcode be inferred from the designated value /// input operand? /// This also implies that this opcode is polymorphic. 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. /// This does not include `variable_args` produced by calls. 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. /// Returns `None` if the instruction is not polymorphic. fn typeset_offset(self) -> Option { - let offset = ((self.0 & 0xff) >> 4) as usize; + let offset = self.typeset_offset as usize; if offset < TYPE_SETS.len() { Some(offset) } else { @@ -453,7 +450,7 @@ impl OpcodeConstraints { /// Get the offset into OPERAND_CONSTRAINTS where the descriptors for this opcode begin. 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