From b2abe74f25b8be6d095698d93d89029c33a32851 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 8 Mar 2021 18:20:05 +0000 Subject: [PATCH 1/3] Improve codegen for remove and swap_remove on EntityList --- cranelift/entity/src/list.rs | 48 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/cranelift/entity/src/list.rs b/cranelift/entity/src/list.rs index 3e583c5fd7..b05afb51a6 100644 --- a/cranelift/entity/src/list.rs +++ b/cranelift/entity/src/list.rs @@ -445,20 +445,8 @@ impl EntityList { } } - /// Removes the element at position `index` from the list. Potentially linear complexity. - pub fn remove(&mut self, index: usize, pool: &mut ListPool) { - let len; - { - let seq = self.as_mut_slice(pool); - len = seq.len(); - debug_assert!(index < len); - - // Copy elements down. - for i in index..len - 1 { - seq[i] = seq[i + 1]; - } - } - + /// Removes the last element from the list. + fn remove_last(&mut self, len: usize, pool: &mut ListPool) { // Check if we deleted the last element. if len == 1 { self.clear(pool); @@ -477,20 +465,34 @@ impl EntityList { pool.data[block] = T::new(len - 1); } + /// Removes the element at position `index` from the list. Potentially linear complexity. + pub fn remove(&mut self, index: usize, pool: &mut ListPool) { + let len; + { + let seq = self.as_mut_slice(pool); + len = seq.len(); + debug_assert!(index < len); + + // Copy elements down. + for i in index..len - 1 { + seq[i] = seq[i + 1]; + } + } + + self.remove_last(len, pool); + } + /// Removes the element at `index` in constant time by switching it with the last element of /// the list. pub fn swap_remove(&mut self, index: usize, pool: &mut ListPool) { - let len = self.len(pool); + let seq = self.as_mut_slice(pool); + let len = seq.len(); debug_assert!(index < len); - if index == len - 1 { - self.remove(index, pool); - } else { - { - let seq = self.as_mut_slice(pool); - seq.swap(index, len - 1); - } - self.remove(len - 1, pool); + if index != len - 1 { + seq.swap(index, len - 1); } + + self.remove_last(len, pool); } /// Grow the list by inserting `count` elements at `index`. From 65d0bc58d29d2d4c467cd3f8618265c66e852f49 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 8 Mar 2021 18:20:46 +0000 Subject: [PATCH 2/3] Add EntityList::deep_clone --- cranelift/entity/src/list.rs | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/cranelift/entity/src/list.rs b/cranelift/entity/src/list.rs index b05afb51a6..bc4002f252 100644 --- a/cranelift/entity/src/list.rs +++ b/cranelift/entity/src/list.rs @@ -307,6 +307,24 @@ impl EntityList { self.as_mut_slice(pool).get_mut(index) } + /// Create a deep clone of the list, which does not alias the original list. + pub fn deep_clone(&self, pool: &mut ListPool) -> Self { + match pool.len_of(self) { + None => return Self::new(), + Some(len) => { + let src = self.index as usize; + let block = pool.alloc(sclass_for_length(len)); + pool.data[block] = T::new(len); + pool.data.copy_within(src..src + len, block + 1); + + Self { + index: (block + 1) as u32, + unused: PhantomData, + } + } + } + } + /// Removes all elements from the list. /// /// The memory used by the list is put back in the pool. @@ -738,4 +756,23 @@ mod tests { list.as_mut_slice(pool)[3] = i4; assert_eq!(list.as_slice(pool), &[i2, i1, i3, i4]); } + + #[test] + fn deep_clone() { + let pool = &mut ListPool::::new(); + + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + let i4 = Inst::new(4); + + let mut list1 = EntityList::from_slice(&[i1, i2, i3], pool); + let list2 = list1.deep_clone(pool); + assert_eq!(list1.as_slice(pool), &[i1, i2, i3]); + assert_eq!(list2.as_slice(pool), &[i1, i2, i3]); + + list1.as_mut_slice(pool)[0] = i4; + assert_eq!(list1.as_slice(pool), &[i4, i2, i3]); + assert_eq!(list2.as_slice(pool), &[i1, i2, i3]); + } } From 9b1693aa72f30cec1e14a70c73d16c07c9c71428 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 8 Mar 2021 18:21:02 +0000 Subject: [PATCH 3/3] Add EntityList::truncate --- cranelift/entity/src/list.rs | 52 ++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/cranelift/entity/src/list.rs b/cranelift/entity/src/list.rs index bc4002f252..d37ea8ae09 100644 --- a/cranelift/entity/src/list.rs +++ b/cranelift/entity/src/list.rs @@ -513,6 +513,37 @@ impl EntityList { self.remove_last(len, pool); } + /// Shortens the list down to `len` elements. + /// + /// Does nothing if the list is already shorter than `len`. + pub fn truncate(&mut self, new_len: usize, pool: &mut ListPool) { + if new_len == 0 { + self.clear(pool); + return; + } + + match pool.len_of(self) { + None => return, + Some(len) => { + if len <= new_len { + return; + } + + let block; + let idx = self.index as usize; + let sclass = sclass_for_length(len); + let new_sclass = sclass_for_length(new_len); + if sclass != new_sclass { + block = pool.realloc(idx - 1, sclass, new_sclass, new_len + 1); + self.index = (block + 1) as u32; + } else { + block = idx - 1; + } + pool.data[block] = T::new(new_len); + } + } + } + /// Grow the list by inserting `count` elements at `index`. /// /// The new elements are not initialized, they will contain whatever happened to be in memory. @@ -775,4 +806,25 @@ mod tests { assert_eq!(list1.as_slice(pool), &[i4, i2, i3]); assert_eq!(list2.as_slice(pool), &[i1, i2, i3]); } + + #[test] + fn truncate() { + let pool = &mut ListPool::::new(); + + let i1 = Inst::new(1); + let i2 = Inst::new(2); + let i3 = Inst::new(3); + let i4 = Inst::new(4); + + let mut list = EntityList::from_slice(&[i1, i2, i3, i4, i1, i2, i3, i4], pool); + assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2, i3, i4]); + list.truncate(6, pool); + assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2]); + list.truncate(9, pool); + assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2]); + list.truncate(2, pool); + assert_eq!(list.as_slice(pool), &[i1, i2]); + list.truncate(0, pool); + assert!(list.is_empty()); + } }