diff --git a/lib/cretonne/meta/gen_instr.py b/lib/cretonne/meta/gen_instr.py index e6eaa82c32..02677bfdbd 100644 --- a/lib/cretonne/meta/gen_instr.py +++ b/lib/cretonne/meta/gen_instr.py @@ -439,6 +439,7 @@ def gen_type_constraints(fmt, instrs): get_constraint(i.ins[opnum], ctrl_typevar, type_sets)) offset = operand_seqs.add(constraints) fixed_results = len(i.value_results) + fixed_values = len(i.value_opnums) # Can the controlling type variable be inferred from the designated # operand? use_typevar_operand = i.is_polymorphic and i.use_typevar_operand @@ -449,10 +450,10 @@ def gen_type_constraints(fmt, instrs): # result? requires_typevar_operand = use_typevar_operand and not use_result fmt.comment( - ('{}: fixed_results={}, use_typevar_operand={}, ' + - 'requires_typevar_operand={}') + '{}: fixed_results={}, use_typevar_operand={}, ' + 'requires_typevar_operand={}, fixed_values={}' .format(i.camel_name, fixed_results, use_typevar_operand, - requires_typevar_operand)) + requires_typevar_operand, fixed_values)) fmt.comment('Constraints={}'.format(constraints)) if i.is_polymorphic: fmt.comment( @@ -464,6 +465,8 @@ def gen_type_constraints(fmt, instrs): flags |= 8 if requires_typevar_operand: flags |= 0x10 + assert fixed_values < 8, "Bit field encoding too tight" + flags |= fixed_values << 5 with fmt.indented('OpcodeConstraints {', '},'): fmt.line('flags: {:#04x},'.format(flags)) diff --git a/lib/cretonne/src/ir/instructions.rs b/lib/cretonne/src/ir/instructions.rs index de34a708c9..7e970f73b8 100644 --- a/lib/cretonne/src/ir/instructions.rs +++ b/lib/cretonne/src/ir/instructions.rs @@ -387,6 +387,9 @@ pub struct OpcodeConstraints { /// Bit 4: /// This opcode is polymorphic and the controlling type variable does *not* appear as the /// first result type. + /// + /// Bits 5-7: + /// Number of fixed value arguments. The minimum required number of value operands. flags: u8, /// Permitted set of types for the controlling type variable as an index into `TYPE_SETS`. @@ -423,6 +426,17 @@ impl OpcodeConstraints { (self.flags & 0x7) as usize } + /// Get the number of *fixed* input values required by this opcode. + /// + /// This does not include `variable_args` arguments on call and branch instructions. + /// + /// The number of fixed input values is usually implied by the instruction format, but + /// instruction formats that use a `ValueList` put both fixed and variable arguments in the + /// list. This method returns the *minimum* number of values required in the value list. + pub fn fixed_value_arguments(self) -> usize { + ((self.flags >> 5) & 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 { @@ -609,6 +623,22 @@ mod tests { assert_eq!(mem::size_of::(), 16); } + #[test] + fn constraints() { + let a = Opcode::Iadd.constraints(); + assert!(a.use_typevar_operand()); + assert_eq!(a.fixed_results(), 1); + assert_eq!(a.fixed_value_arguments(), 2); + + let c = Opcode::Call.constraints(); + assert_eq!(c.fixed_results(), 0); + assert_eq!(c.fixed_value_arguments(), 0); + + let i = Opcode::CallIndirect.constraints(); + assert_eq!(i.fixed_results(), 0); + assert_eq!(i.fixed_value_arguments(), 1); + } + #[test] fn value_set() { use ir::types::*;