diff --git a/lib/cretonne/meta/gen_instr.py b/lib/cretonne/meta/gen_instr.py index 8b4555d9b2..569eca71b7 100644 --- a/lib/cretonne/meta/gen_instr.py +++ b/lib/cretonne/meta/gen_instr.py @@ -9,6 +9,7 @@ import cretonne def gen_formats(fmt): + # type: (srcgen.Formatter) -> None """Generate an instruction format enumeration""" fmt.doc_comment('An instruction format') @@ -38,7 +39,63 @@ def gen_formats(fmt): fmt.line() +def gen_arguments_method(fmt, is_mut): + # type: (srcgen.Formatter, bool) -> None + method = 'arguments' + mut = '' + rslice = 'ref_slice' + if is_mut: + method += '_mut' + mut = 'mut ' + rslice += '_mut' + + with fmt.indented( + 'pub fn {f}(&{m}self) -> [&{m}[Value]; 2] {{' + .format(f=method, m=mut), '}'): + with fmt.indented('match *self {', '}'): + for f in cretonne.InstructionFormat.all_formats: + n = 'InstructionData::' + f.name + has_varargs = cretonne.variable_args in f.kinds + # Formats with both fixed and variable arguments delegate to + # the data struct. We need to work around borrow checker quirks + # when extracting two mutable references. + if has_varargs and len(f.value_operands) > 0: + fmt.line( + '{} {{ ref {}data, .. }} => data.{}(),' + .format(n, mut, method)) + continue + # Fixed args. + if len(f.value_operands) == 0: + arg = '&{}[]'.format(mut) + capture = '' + elif len(f.value_operands) == 1: + if f.boxed_storage: + capture = 'ref {}data, '.format(mut) + arg = '{}(&{}data.arg)'.format(rslice, mut) + else: + capture = 'ref {}arg, '.format(mut) + arg = '{}(arg)'.format(rslice) + else: + if f.boxed_storage: + capture = 'ref {}data, '.format(mut) + arg = '&{}data.args'.format(mut) + else: + capture = 'ref {}args, '.format(mut) + arg = 'args' + # Varargs. + if cretonne.variable_args in f.kinds: + varg = '&{}data.varargs'.format(mut) + capture = 'ref {}data, '.format(mut) + else: + varg = '&{}[]'.format(mut) + + fmt.line( + '{} {{ {} .. }} => [{}, {}],' + .format(n, capture, arg, varg)) + + def gen_instruction_data_impl(fmt): + # type: (srcgen.Formatter) -> None """ Generate the boring parts of the InstructionData implementation. @@ -49,6 +106,7 @@ def gen_instruction_data_impl(fmt): - `pub fn first_type(&self) -> Type` - `pub fn second_result(&self) -> Option` - `pub fn second_result_mut<'a>(&'a mut self) -> Option<&'a mut Value>` + - `pub fn arguments(&self) -> (&[Value], &[Value])` """ # The `opcode` and `first_type` methods simply read the `opcode` and `ty` @@ -148,6 +206,22 @@ def gen_instruction_data_impl(fmt): ' {{ ref args, .. }} => Some(args[{}]),' .format(i)) + fmt.doc_comment( + """ + Get the value arguments to this instruction. + + This is returned as two `Value` slices. The first one + represents the fixed arguments, the second any variable + arguments. + """) + gen_arguments_method(fmt, False) + fmt.doc_comment( + """ + Get mutable references to the value arguments to this + instruction. + """) + gen_arguments_method(fmt, True) + def collect_instr_groups(isas): seen = set() diff --git a/lib/cretonne/src/ir/instructions.rs b/lib/cretonne/src/ir/instructions.rs index f601169beb..b8c5bdc4fa 100644 --- a/lib/cretonne/src/ir/instructions.rs +++ b/lib/cretonne/src/ir/instructions.rs @@ -15,6 +15,8 @@ use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, ImmVector}; use ir::condcodes::*; use ir::types; +use ref_slice::*; + // Include code generated by `lib/cretonne/meta/gen_instr.py`. This file contains: // // - The `pub enum InstructionFormat` enum with all the instruction formats. @@ -339,6 +341,18 @@ pub struct BranchData { pub varargs: VariableArgs, } +impl BranchData { + /// Get references to the arguments. + pub fn arguments(&self) -> [&[Value]; 2] { + [ref_slice(&self.arg), &self.varargs] + } + + /// Get mutable references to the arguments. + pub fn arguments_mut(&mut self) -> [&mut [Value]; 2] { + [ref_slice_mut(&mut self.arg), &mut self.varargs] + } +} + impl Display for BranchData { fn fmt(&self, f: &mut Formatter) -> fmt::Result { try!(write!(f, "{}, {}", self.arg, self.destination)); @@ -372,6 +386,18 @@ pub struct IndirectCallData { pub varargs: VariableArgs, } +impl IndirectCallData { + /// Get references to the arguments. + pub fn arguments(&self) -> [&[Value]; 2] { + [ref_slice(&self.arg), &self.varargs] + } + + /// Get mutable references to the arguments. + pub fn arguments_mut(&mut self) -> [&mut [Value]; 2] { + [ref_slice_mut(&mut self.arg), &mut self.varargs] + } +} + /// Payload of a return instruction. #[derive(Clone, Debug)] pub struct ReturnData { @@ -381,9 +407,33 @@ pub struct ReturnData { /// Analyzing an instruction. /// -/// Avoid large matches on instruction formats by using the methods efined here to examine +/// Avoid large matches on instruction formats by using the methods defined here to examine /// instructions. impl InstructionData { + /// Execute a closure once for each argument to this instruction. + /// See also the `arguments()` method. + pub fn each_arg(&self, func: F) + where F: Fn(Value) + { + for part in &self.arguments() { + for &arg in part.iter() { + func(arg); + } + } + } + + /// Execute a closure with a mutable reference to each argument to this instruction. + /// See also the `arguments_mut()` method. + pub fn each_arg_mut(&mut self, func: F) + where F: Fn(&mut Value) + { + for part in &mut self.arguments_mut() { + for arg in part.iter_mut() { + func(arg); + } + } + } + /// Return information about the destination of a branch or jump instruction. /// /// Any instruction that can transfer control to another EBB reveals its possible destinations