diff --git a/lib/cretonne/meta/gen_instr.py b/lib/cretonne/meta/gen_instr.py index c05cb51078..e6eaa82c32 100644 --- a/lib/cretonne/meta/gen_instr.py +++ b/lib/cretonne/meta/gen_instr.py @@ -111,6 +111,8 @@ def gen_instruction_data_impl(fmt): - `pub fn second_result_mut(&mut self) -> Option<&mut PackedOption>` - `pub fn arguments(&self, &pool) -> &[Value]` - `pub fn arguments_mut(&mut self, &pool) -> &mut [Value]` + - `pub fn take_value_list(&mut self) -> Option` + - `pub fn put_value_list(&mut self, args: ValueList>` """ # The `opcode` and `first_type` methods simply read the `opcode` and `ty` @@ -221,6 +223,45 @@ def gen_instruction_data_impl(fmt): """) gen_arguments_method(fmt, True) + fmt.doc_comment( + """ + Take out the value list with all the value arguments and return + it. + + This leaves the value list in the instruction empty. Use + `put_value_list` to put the value list back. + """) + with fmt.indented( + 'pub fn take_value_list(&mut self) -> Option {', + '}'): + with fmt.indented('match *self {', '}'): + for f in InstructionFormat.all_formats: + n = 'InstructionData::' + f.name + if f.has_value_list: + fmt.line( + n + ' { ref mut args, .. } => Some(args.take()),') + fmt.line('_ => None,') + + fmt.doc_comment( + """ + Put back a value list. + + After removing a value list with `take_value_list()`, use this + method to put it back. It is required that this instruction has + a format that accepts a value list, and that the existing value + list is empty. This avoids leaking list pool memory. + """) + with fmt.indented( + 'pub fn put_value_list(&mut self, vlist: ValueList) {', '}'): + with fmt.indented('let args = match *self {', '};'): + for f in InstructionFormat.all_formats: + n = 'InstructionData::' + f.name + if f.has_value_list: + fmt.line(n + ' { ref mut args, .. } => args,') + fmt.line('_ => panic!("No value list: {:?}", self),') + fmt.line('assert!(args.is_empty(), "Value list already in use");') + fmt.line('*args = vlist;') + def collect_instr_groups(isas): seen = set() diff --git a/lib/cretonne/src/entity_list.rs b/lib/cretonne/src/entity_list.rs index 2b8ebb783e..64a0a4c830 100644 --- a/lib/cretonne/src/entity_list.rs +++ b/lib/cretonne/src/entity_list.rs @@ -47,6 +47,7 @@ //! reserved for the empty list which isn't allocated in the vector. use std::marker::PhantomData; +use std::mem; use entity_map::EntityRef; @@ -273,6 +274,13 @@ impl EntityList { self.index = 0; } + /// Take all elements from this list and return them as a new list. Leave this list empty. + /// + /// This is the equivalent of `Option::take()`. + pub fn take(&mut self) -> EntityList { + mem::replace(self, Default::default()) + } + /// Appends an element to the back of the list. pub fn push(&mut self, element: T, pool: &mut ListPool) { let idx = self.index as usize;