diff --git a/lib/cretonne/src/entity/iter.rs b/lib/cretonne/src/entity/iter.rs new file mode 100644 index 0000000000..156021ee86 --- /dev/null +++ b/lib/cretonne/src/entity/iter.rs @@ -0,0 +1,109 @@ +//! A double-ended iterator over entity references and entities. + +use entity::EntityRef; +use std::marker::PhantomData; +use std::slice; + +/// Iterate over all keys in order. +pub struct Iter<'a, K: EntityRef, V> +where + V: 'a, +{ + pos: usize, + iter: slice::Iter<'a, V>, + unused: PhantomData, +} + +impl<'a, K: EntityRef, V> Iter<'a, K, V> { + /// Create an `Iter` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(key: K, iter: slice::Iter<'a, V>) -> Self { + Self { + pos: key.index(), + iter, + unused: PhantomData, + } + } +} + +impl<'a, K: EntityRef, V> Iterator for Iter<'a, K, V> { + type Item = (K, &'a V); + + fn next(&mut self) -> Option { + if let Some(next) = self.iter.next() { + let pos = self.pos; + self.pos += 1; + Some((K::new(pos), next)) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a, K: EntityRef, V> DoubleEndedIterator for Iter<'a, K, V> { + fn next_back(&mut self) -> Option { + if let Some(next_back) = self.iter.next_back() { + Some((K::new(self.pos), next_back)) + } else { + None + } + } +} + +impl<'a, K: EntityRef, V> ExactSizeIterator for Iter<'a, K, V> {} + +/// Iterate over all keys in order. +pub struct IterMut<'a, K: EntityRef, V> +where + V: 'a, +{ + pos: usize, + iter: slice::IterMut<'a, V>, + unused: PhantomData, +} + +impl<'a, K: EntityRef, V> IterMut<'a, K, V> { + /// Create an `IterMut` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(key: K, iter: slice::IterMut<'a, V>) -> Self { + Self { + pos: key.index(), + iter, + unused: PhantomData, + } + } +} + +impl<'a, K: EntityRef, V> Iterator for IterMut<'a, K, V> { + type Item = (K, &'a mut V); + + fn next(&mut self) -> Option { + if let Some(next) = self.iter.next() { + let pos = self.pos; + self.pos += 1; + Some((K::new(pos), next)) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a, K: EntityRef, V> DoubleEndedIterator for IterMut<'a, K, V> { + fn next_back(&mut self) -> Option { + if let Some(next_back) = self.iter.next_back() { + Some((K::new(self.pos), next_back)) + } else { + None + } + } +} + +impl<'a, K: EntityRef, V> ExactSizeIterator for IterMut<'a, K, V> {} diff --git a/lib/cretonne/src/entity/map.rs b/lib/cretonne/src/entity/map.rs index f251c2f831..3aac22b44f 100644 --- a/lib/cretonne/src/entity/map.rs +++ b/lib/cretonne/src/entity/map.rs @@ -1,9 +1,10 @@ //! Densely numbered entity references as mapping keys. -use entity::{EntityRef, Keys}; +use entity::{EntityRef, Keys, Iter, IterMut}; use std::marker::PhantomData; use std::ops::{Index, IndexMut}; use std::vec::Vec; +use std::slice; /// A mapping `K -> V` for densely indexed entity references. /// @@ -68,11 +69,31 @@ where self.elems.clear() } + /// Iterate over all the keys and values in this map. + pub fn iter(&self) -> Iter { + Iter::new(K::new(0), self.elems.iter()) + } + + /// Iterate over all the keys and values in this map, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(K::new(0), self.elems.iter_mut()) + } + /// Iterate over all the keys in this map. pub fn keys(&self) -> Keys { Keys::new(self.elems.len()) } + /// Iterate over all the keys in this map. + pub fn values(&self) -> slice::Iter { + self.elems.iter() + } + + /// Iterate over all the keys in this map, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.elems.iter_mut() + } + /// Resize the map to have `n` entries by adding default entries as needed. pub fn resize(&mut self, n: usize) { self.elems.resize(n, self.default.clone()); diff --git a/lib/cretonne/src/entity/mod.rs b/lib/cretonne/src/entity/mod.rs index 6457e47f56..c4004f126d 100644 --- a/lib/cretonne/src/entity/mod.rs +++ b/lib/cretonne/src/entity/mod.rs @@ -30,6 +30,7 @@ //! `Vec`. mod keys; +mod iter; mod list; mod map; mod primary; @@ -37,6 +38,7 @@ mod sparse; mod set; pub use self::keys::Keys; +pub use self::iter::{Iter, IterMut}; pub use self::list::{EntityList, ListPool}; pub use self::map::EntityMap; pub use self::primary::PrimaryMap; diff --git a/lib/cretonne/src/entity/primary.rs b/lib/cretonne/src/entity/primary.rs index c06b818355..8671bdf809 100644 --- a/lib/cretonne/src/entity/primary.rs +++ b/lib/cretonne/src/entity/primary.rs @@ -1,8 +1,9 @@ //! Densely numbered entity references as mapping keys. -use entity::{EntityRef, Keys}; +use entity::{EntityRef, Keys, Iter, IterMut}; use std::marker::PhantomData; use std::ops::{Index, IndexMut}; use std::vec::Vec; +use std::slice; /// A primary mapping `K -> V` allocating dense entity references. /// @@ -59,6 +60,26 @@ where Keys::new(self.elems.len()) } + /// Iterate over all the values in this map. + pub fn values(&self) -> slice::Iter { + self.elems.iter() + } + + /// Iterate over all the values in this map, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.elems.iter_mut() + } + + /// Iterate over all the keys and values in this map. + pub fn iter(&self) -> Iter { + Iter::new(K::new(0), self.elems.iter()) + } + + /// Iterate over all the keys and values in this map, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(K::new(0), self.elems.iter_mut()) + } + /// Remove all entries from this map. pub fn clear(&mut self) { self.elems.clear() @@ -133,13 +154,80 @@ mod tests { #[test] fn push() { let mut m = PrimaryMap::new(); - let k1: E = m.push(12); - let k2 = m.push(33); + let k0: E = m.push(12); + let k1 = m.push(33); - assert_eq!(m[k1], 12); - assert_eq!(m[k2], 33); + assert_eq!(m[k0], 12); + assert_eq!(m[k1], 33); let v: Vec = m.keys().collect(); - assert_eq!(v, [k1, k2]); + assert_eq!(v, [k0, k1]); + } + + #[test] + fn iter() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for (key, value) in m.iter() { + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for (key_mut, value_mut) in m.iter_mut() { + assert_eq!(key_mut.index(), i); + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn keys() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for key in m.keys() { + assert_eq!(key.index(), i); + i += 1; + } + } + + #[test] + fn values() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for value in m.values() { + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for value_mut in m.values_mut() { + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } } } diff --git a/lib/cretonne/src/ir/stackslot.rs b/lib/cretonne/src/ir/stackslot.rs index 5f73fb4b37..bc87e11a82 100644 --- a/lib/cretonne/src/ir/stackslot.rs +++ b/lib/cretonne/src/ir/stackslot.rs @@ -3,11 +3,12 @@ //! The `StackSlotData` struct keeps track of a single stack slot in a function. //! -use entity::{PrimaryMap, Keys}; +use entity::{PrimaryMap, Keys, Iter, IterMut}; use ir::{Type, StackSlot}; use packed_option::PackedOption; use std::cmp; use std::fmt; +use std::slice; use std::ops::{Index, IndexMut}; use std::str::FromStr; use std::vec::Vec; @@ -208,6 +209,26 @@ impl StackSlots { self.slots[ss].offset = Some(offset); } + /// Get an iterator over all the stack slot keys. + pub fn iter(&self) -> Iter { + self.slots.iter() + } + + /// Get an iterator over all the stack slot keys, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + self.slots.iter_mut() + } + + /// Get an iterator over all the stack slot records. + pub fn values(&self) -> slice::Iter { + self.slots.values() + } + + /// Get an iterator over all the stack slot records, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.slots.values_mut() + } + /// Get an iterator over all the stack slot keys. pub fn keys(&self) -> Keys { self.slots.keys() diff --git a/lib/cretonne/src/legalizer/boundary.rs b/lib/cretonne/src/legalizer/boundary.rs index 0c5479650c..e1e4a17956 100644 --- a/lib/cretonne/src/legalizer/boundary.rs +++ b/lib/cretonne/src/legalizer/boundary.rs @@ -35,9 +35,9 @@ use std::vec::Vec; pub fn legalize_signatures(func: &mut Function, isa: &TargetIsa) { isa.legalize_signature(&mut func.signature, true); func.signature.compute_argument_bytes(); - for sig in func.dfg.signatures.keys() { - isa.legalize_signature(&mut func.dfg.signatures[sig], false); - func.dfg.signatures[sig].compute_argument_bytes(); + for sig_data in func.dfg.signatures.values_mut() { + isa.legalize_signature(sig_data, false); + sig_data.compute_argument_bytes(); } if let Some(entry) = func.layout.entry_block() { diff --git a/lib/cretonne/src/legalizer/libcall.rs b/lib/cretonne/src/legalizer/libcall.rs index c4d063bd3c..2bb0f1292c 100644 --- a/lib/cretonne/src/legalizer/libcall.rs +++ b/lib/cretonne/src/legalizer/libcall.rs @@ -29,8 +29,8 @@ pub fn expand_as_libcall(inst: ir::Inst, func: &mut ir::Function) -> bool { fn find_funcref(libcall: ir::LibCall, func: &ir::Function) -> Option { // We're assuming that all libcall function decls are at the end. // If we get this wrong, worst case we'll have duplicate libcall decls which is harmless. - for fref in func.dfg.ext_funcs.keys().rev() { - match func.dfg.ext_funcs[fref].name { + for (fref, func_data) in func.dfg.ext_funcs.iter().rev() { + match func_data.name { ir::ExternalName::LibCall(lc) => { if lc == libcall { return Some(fref); diff --git a/lib/cretonne/src/stack_layout.rs b/lib/cretonne/src/stack_layout.rs index f1cf35f150..0cf6e77527 100644 --- a/lib/cretonne/src/stack_layout.rs +++ b/lib/cretonne/src/stack_layout.rs @@ -39,9 +39,7 @@ pub fn layout_stack(frame: &mut StackSlots, alignment: StackSize) -> Result max_size { return Err(CtonError::ImplLimitExceeded); } @@ -72,9 +70,7 @@ pub fn layout_stack(frame: &mut StackSlots, alignment: StackSize) -> Result Result result::Result { let mut any = false; - for ss in func.stack_slots.keys() { + for (ss, slot) in func.stack_slots.iter() { any = true; - writeln!(w, " {} = {}", ss, func.stack_slots[ss])?; + writeln!(w, " {} = {}", ss, slot)?; } - for gv in func.global_vars.keys() { + for (gv, gv_data) in func.global_vars.iter() { any = true; - writeln!(w, " {} = {}", gv, func.global_vars[gv])?; + writeln!(w, " {} = {}", gv, gv_data)?; } - for heap in func.heaps.keys() { + for (heap, heap_data) in func.heaps.iter() { any = true; - writeln!(w, " {} = {}", heap, func.heaps[heap])?; + writeln!(w, " {} = {}", heap, heap_data)?; } // Write out all signatures before functions since function declarations can refer to // signatures. - for sig in func.dfg.signatures.keys() { + for (sig, sig_data) in func.dfg.signatures.iter() { any = true; - writeln!( - w, - " {} = {}", - sig, - func.dfg.signatures[sig].display(regs) - )?; + writeln!(w, " {} = {}", sig, sig_data.display(regs))?; } - for fnref in func.dfg.ext_funcs.keys() { + for (fnref, ext_func) in func.dfg.ext_funcs.iter() { any = true; - let ext_func = &func.dfg.ext_funcs[fnref]; if ext_func.signature != SigRef::reserved_value() { writeln!(w, " {} = {}", fnref, ext_func)?; } } - for jt in func.jump_tables.keys() { + for (jt, jt_data) in func.jump_tables.iter() { any = true; - writeln!(w, " {} = {}", jt, func.jump_tables[jt])?; + writeln!(w, " {} = {}", jt, jt_data)?; } Ok(any) diff --git a/lib/filetests/src/test_binemit.rs b/lib/filetests/src/test_binemit.rs index c22f1ed386..81e48f84fe 100644 --- a/lib/filetests/src/test_binemit.rs +++ b/lib/filetests/src/test_binemit.rs @@ -130,8 +130,8 @@ impl SubTest for TestBinEmit { // Fix the stack frame layout so we can test spill/fill encodings. let min_offset = func.stack_slots - .keys() - .map(|ss| func.stack_slots[ss].offset.unwrap()) + .values() + .map(|slot| slot.offset.unwrap()) .min(); func.stack_slots.frame_size = min_offset.map(|off| (-off) as u32); diff --git a/lib/frontend/src/frontend.rs b/lib/frontend/src/frontend.rs index bd01ce1893..37d2fe0206 100644 --- a/lib/frontend/src/frontend.rs +++ b/lib/frontend/src/frontend.rs @@ -439,14 +439,14 @@ where pub fn finalize(&mut self) { // Check that all the `Ebb`s are filled and sealed. debug_assert!( - self.func_ctx.ebbs.keys().all(|ebb| { - self.func_ctx.ebbs[ebb].pristine || self.func_ctx.ssa.is_sealed(ebb) + self.func_ctx.ebbs.iter().all(|(ebb, ebb_data)| { + ebb_data.pristine || self.func_ctx.ssa.is_sealed(ebb) }), "all blocks should be sealed before dropping a FunctionBuilder" ); debug_assert!( - self.func_ctx.ebbs.keys().all(|ebb| { - self.func_ctx.ebbs[ebb].pristine || self.func_ctx.ebbs[ebb].filled + self.func_ctx.ebbs.values().all(|ebb_data| { + ebb_data.pristine || ebb_data.filled }), "all blocks should be filled before dropping a FunctionBuilder" );