Add OpcodeConstraints::fixed_value_arguments()
Now that some instruction formats put all of their value arguments in a value list, we need to know how many value are fixed and how many are variable_args. CC @angusholder who may need this information in the verifier.
This commit is contained in:
@@ -439,6 +439,7 @@ def gen_type_constraints(fmt, instrs):
|
|||||||
get_constraint(i.ins[opnum], ctrl_typevar, type_sets))
|
get_constraint(i.ins[opnum], ctrl_typevar, type_sets))
|
||||||
offset = operand_seqs.add(constraints)
|
offset = operand_seqs.add(constraints)
|
||||||
fixed_results = len(i.value_results)
|
fixed_results = len(i.value_results)
|
||||||
|
fixed_values = len(i.value_opnums)
|
||||||
# Can the controlling type variable be inferred from the designated
|
# Can the controlling type variable be inferred from the designated
|
||||||
# operand?
|
# operand?
|
||||||
use_typevar_operand = i.is_polymorphic and i.use_typevar_operand
|
use_typevar_operand = i.is_polymorphic and i.use_typevar_operand
|
||||||
@@ -449,10 +450,10 @@ def gen_type_constraints(fmt, instrs):
|
|||||||
# result?
|
# result?
|
||||||
requires_typevar_operand = use_typevar_operand and not use_result
|
requires_typevar_operand = use_typevar_operand and not use_result
|
||||||
fmt.comment(
|
fmt.comment(
|
||||||
('{}: fixed_results={}, use_typevar_operand={}, ' +
|
'{}: fixed_results={}, use_typevar_operand={}, '
|
||||||
'requires_typevar_operand={}')
|
'requires_typevar_operand={}, fixed_values={}'
|
||||||
.format(i.camel_name, fixed_results, use_typevar_operand,
|
.format(i.camel_name, fixed_results, use_typevar_operand,
|
||||||
requires_typevar_operand))
|
requires_typevar_operand, fixed_values))
|
||||||
fmt.comment('Constraints={}'.format(constraints))
|
fmt.comment('Constraints={}'.format(constraints))
|
||||||
if i.is_polymorphic:
|
if i.is_polymorphic:
|
||||||
fmt.comment(
|
fmt.comment(
|
||||||
@@ -464,6 +465,8 @@ def gen_type_constraints(fmt, instrs):
|
|||||||
flags |= 8
|
flags |= 8
|
||||||
if requires_typevar_operand:
|
if requires_typevar_operand:
|
||||||
flags |= 0x10
|
flags |= 0x10
|
||||||
|
assert fixed_values < 8, "Bit field encoding too tight"
|
||||||
|
flags |= fixed_values << 5
|
||||||
|
|
||||||
with fmt.indented('OpcodeConstraints {', '},'):
|
with fmt.indented('OpcodeConstraints {', '},'):
|
||||||
fmt.line('flags: {:#04x},'.format(flags))
|
fmt.line('flags: {:#04x},'.format(flags))
|
||||||
|
|||||||
@@ -387,6 +387,9 @@ pub struct OpcodeConstraints {
|
|||||||
/// Bit 4:
|
/// Bit 4:
|
||||||
/// This opcode is polymorphic and the controlling type variable does *not* appear as the
|
/// This opcode is polymorphic and the controlling type variable does *not* appear as the
|
||||||
/// first result type.
|
/// first result type.
|
||||||
|
///
|
||||||
|
/// Bits 5-7:
|
||||||
|
/// Number of fixed value arguments. The minimum required number of value operands.
|
||||||
flags: u8,
|
flags: u8,
|
||||||
|
|
||||||
/// Permitted set of types for the controlling type variable as an index into `TYPE_SETS`.
|
/// 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
|
(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.
|
/// 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> {
|
||||||
@@ -609,6 +623,22 @@ mod tests {
|
|||||||
assert_eq!(mem::size_of::<InstructionData>(), 16);
|
assert_eq!(mem::size_of::<InstructionData>(), 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]
|
#[test]
|
||||||
fn value_set() {
|
fn value_set() {
|
||||||
use ir::types::*;
|
use ir::types::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user