diff --git a/cranelift/src/filetest/binemit.rs b/cranelift/src/filetest/binemit.rs index 09a6955b5e..af6e72f21e 100644 --- a/cranelift/src/filetest/binemit.rs +++ b/cranelift/src/filetest/binemit.rs @@ -107,11 +107,11 @@ impl SubTest for TestBinEmit { // Give an encoding to any instruction that doesn't already have one. for ebb in func.layout.ebbs() { for inst in func.layout.ebb_insts(ebb) { - if !func.encodings.get_or_default(inst).is_legal() { + if !func.encodings[inst].is_legal() { if let Ok(enc) = isa.encode(&func.dfg, &func.dfg[inst], func.dfg.ctrl_typevar(inst)) { - *func.encodings.ensure(inst) = enc; + func.encodings[inst] = enc; } } } @@ -158,7 +158,7 @@ impl SubTest for TestBinEmit { ebb); for inst in func.layout.ebb_insts(ebb) { sink.text.clear(); - let enc = func.encodings.get_or_default(inst); + let enc = func.encodings[inst]; // Send legal encodings into the emitter. if enc.is_legal() { diff --git a/lib/cretonne/src/binemit/relaxation.rs b/lib/cretonne/src/binemit/relaxation.rs index e49b534624..51d288703c 100644 --- a/lib/cretonne/src/binemit/relaxation.rs +++ b/lib/cretonne/src/binemit/relaxation.rs @@ -67,7 +67,7 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> Result ir::InstInserterBase<'c> for &'c mut EncCursor<'f> { // Assign an encoding. match self.isa .encode(&self.func.dfg, &self.func.dfg[inst], ctrl_typevar) { - Ok(e) => *self.func.encodings.ensure(inst) = e, + Ok(e) => self.func.encodings[inst] = e, Err(_) => panic!("can't encode {}", self.display_inst(inst)), } diff --git a/lib/cretonne/src/dominator_tree.rs b/lib/cretonne/src/dominator_tree.rs index d88adbd4a0..bb80bd3687 100644 --- a/lib/cretonne/src/dominator_tree.rs +++ b/lib/cretonne/src/dominator_tree.rs @@ -1,6 +1,6 @@ //! A Dominator Tree represented as mappings of Ebbs to their immediate dominator. -use entity_map::EntityMap; +use entity::EntityMap; use flowgraph::{ControlFlowGraph, BasicBlock}; use ir::{Ebb, Inst, Function, Layout, ProgramOrder, ExpandedProgramPoint}; use packed_option::PackedOption; @@ -339,7 +339,7 @@ impl DominatorTree { pub fn recompute_split_ebb(&mut self, old_ebb: Ebb, new_ebb: Ebb, split_jump_inst: Inst) { if !self.is_reachable(old_ebb) { // old_ebb is unreachable, it stays so and new_ebb is unreachable too - *self.nodes.ensure(new_ebb) = Default::default(); + self.nodes[new_ebb] = Default::default(); return; } // We use the RPO comparison on the postorder list so we invert the operands of the @@ -350,7 +350,7 @@ impl DominatorTree { .binary_search_by(|probe| self.rpo_cmp_ebb(old_ebb, *probe)) .expect("the old ebb is not declared to the dominator tree"); let new_ebb_rpo = self.insert_after_rpo(old_ebb, old_ebb_postorder_index, new_ebb); - *self.nodes.ensure(new_ebb) = DomNode { + self.nodes[new_ebb] = DomNode { rpo_number: new_ebb_rpo, idom: Some(split_jump_inst).into(), }; diff --git a/lib/cretonne/src/entity/keys.rs b/lib/cretonne/src/entity/keys.rs new file mode 100644 index 0000000000..795e896a00 --- /dev/null +++ b/lib/cretonne/src/entity/keys.rs @@ -0,0 +1,55 @@ +//! A double-ended iterator over entity references. + +use entity::EntityRef; +use std::marker::PhantomData; + +/// Iterate over all keys in order. +pub struct Keys { + pos: usize, + rev_pos: usize, + unused: PhantomData, +} + +impl Keys { + /// Create a `Keys` iterator that visits `count` entities starting from 0. + pub fn new(count: usize) -> Keys { + Keys { + pos: 0, + rev_pos: count, + unused: PhantomData, + } + } +} + +impl Iterator for Keys { + type Item = K; + + fn next(&mut self) -> Option { + if self.pos < self.rev_pos { + let k = K::new(self.pos); + self.pos += 1; + Some(k) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + let size = self.rev_pos - self.pos; + (size, Some(size)) + } +} + +impl DoubleEndedIterator for Keys { + fn next_back(&mut self) -> Option { + if self.rev_pos > self.pos { + let k = K::new(self.rev_pos - 1); + self.rev_pos -= 1; + Some(k) + } else { + None + } + } +} + +impl ExactSizeIterator for Keys {} diff --git a/lib/cretonne/src/entity/map.rs b/lib/cretonne/src/entity/map.rs new file mode 100644 index 0000000000..ca6f1ff7d9 --- /dev/null +++ b/lib/cretonne/src/entity/map.rs @@ -0,0 +1,135 @@ +//! Densely numbered entity references as mapping keys. +//! +//! The `EntityMap` data structure uses the dense index space to implement a map with a vector. +//! Unlike `PrimaryMap`, and `EntityMap` can't be used to allocate entity references. It is used to +//! associate secondary information with entities. + +use entity::{EntityRef, Keys}; +use std::marker::PhantomData; +use std::ops::{Index, IndexMut}; + +/// A mapping `K -> V` for densely indexed entity references. +#[derive(Debug, Clone)] +pub struct EntityMap + where K: EntityRef, + V: Clone +{ + elems: Vec, + default: V, + unused: PhantomData, +} + +/// Shared `EntityMap` implementation for all value types. +impl EntityMap + where K: EntityRef, + V: Clone +{ + /// Create a new empty map. + pub fn new() -> Self + where V: Default + { + EntityMap { + elems: Vec::new(), + default: Default::default(), + unused: PhantomData, + } + } + + /// Get the element at `k` if it exists. + pub fn get(&self, k: K) -> Option<&V> { + self.elems.get(k.index()) + } + + /// Is this map completely empty? + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } + + /// Remove all entries from this map. + pub fn clear(&mut self) { + self.elems.clear() + } + + /// Iterate over all the keys in this map. + pub fn keys(&self) -> Keys { + Keys::new(self.elems.len()) + } + + /// 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()); + } +} + +/// Immutable indexing into an `EntityMap`. +/// +/// All keys are permitted. Untouched entries have the default value. +impl Index for EntityMap + where K: EntityRef, + V: Clone +{ + type Output = V; + + fn index(&self, k: K) -> &V { + self.get(k).unwrap_or(&self.default) + } +} + +/// Mutable indexing into an `EntityMap`. +/// +/// The map grows as needed to accommodate new keys. +impl IndexMut for EntityMap + where K: EntityRef, + V: Clone +{ + fn index_mut(&mut self, k: K) -> &mut V { + let i = k.index(); + if i >= self.elems.len() { + self.resize(i + 1); + } + &mut self.elems[i] + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let r2 = E(2); + let mut m = EntityMap::new(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + + m[r2] = 3; + m[r1] = 5; + + assert_eq!(m[r1], 5); + assert_eq!(m[r2], 3); + + let v: Vec = m.keys().collect(); + assert_eq!(v, [r0, r1, r2]); + + let shared = &m; + assert_eq!(shared[r0], 0); + assert_eq!(shared[r1], 5); + assert_eq!(shared[r2], 3); + } +} diff --git a/lib/cretonne/src/entity/mod.rs b/lib/cretonne/src/entity/mod.rs index 26c1e54353..58f900abc4 100644 --- a/lib/cretonne/src/entity/mod.rs +++ b/lib/cretonne/src/entity/mod.rs @@ -5,6 +5,14 @@ //! //! Various data structures based on the entity references are defined in sub-modules. +mod keys; +mod map; +mod primary; + +pub use self::keys::Keys; +pub use self::map::EntityMap; +pub use self::primary::PrimaryMap; + /// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key /// of an `EntityMap` or `SparseMap`. pub trait EntityRef: Copy + Eq { diff --git a/lib/cretonne/src/entity/primary.rs b/lib/cretonne/src/entity/primary.rs new file mode 100644 index 0000000000..e98698f117 --- /dev/null +++ b/lib/cretonne/src/entity/primary.rs @@ -0,0 +1,141 @@ +//! Densely numbered entity references as mapping keys. +//! +//! The `PrimaryMap` data structure uses the dense index space to implement a map with a vector. +//! +//! A primary map contains the main definition of an entity, and it can be used to allocate new +//! entity references with the `push` method. +//! +//! There should only be a single `PrimaryMap` instance for a given `EntityRef` type, otherwise +//! conflicting references will be created. + +use entity::{EntityRef, Keys}; +use std::marker::PhantomData; +use std::ops::{Index, IndexMut}; + +/// A mapping `K -> V` for densely indexed entity references. +#[derive(Debug, Clone)] +pub struct PrimaryMap + where K: EntityRef +{ + elems: Vec, + unused: PhantomData, +} + +impl PrimaryMap + where K: EntityRef +{ + /// Create a new empty map. + pub fn new() -> Self { + PrimaryMap { + elems: Vec::new(), + unused: PhantomData, + } + } + + /// Check if `k` is a valid key in the map. + pub fn is_valid(&self, k: K) -> bool { + k.index() < self.elems.len() + } + + /// Get the element at `k` if it exists. + pub fn get(&self, k: K) -> Option<&V> { + self.elems.get(k.index()) + } + + /// Is this map completely empty? + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } + + /// Get the total number of entity references created. + pub fn len(&self) -> usize { + self.elems.len() + } + + /// Iterate over all the keys in this map. + pub fn keys(&self) -> Keys { + Keys::new(self.elems.len()) + } + + /// Remove all entries from this map. + pub fn clear(&mut self) { + self.elems.clear() + } + + /// Get the key that will be assigned to the next pushed value. + pub fn next_key(&self) -> K { + K::new(self.elems.len()) + } + + /// Append `v` to the mapping, assigning a new key which is returned. + pub fn push(&mut self, v: V) -> K { + let k = self.next_key(); + self.elems.push(v); + k + } +} + +/// Immutable indexing into an `PrimaryMap`. +/// The indexed value must be in the map. +impl Index for PrimaryMap + where K: EntityRef +{ + type Output = V; + + fn index(&self, k: K) -> &V { + &self.elems[k.index()] + } +} + +/// Mutable indexing into an `PrimaryMap`. +impl IndexMut for PrimaryMap + where K: EntityRef +{ + fn index_mut(&mut self, k: K) -> &mut V { + &mut self.elems[k.index()] + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let m = PrimaryMap::::new(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + + assert!(!m.is_valid(r0)); + assert!(!m.is_valid(r1)); + } + + #[test] + fn push() { + let mut m = PrimaryMap::new(); + let k1: E = m.push(12); + let k2 = m.push(33); + + assert_eq!(m[k1], 12); + assert_eq!(m[k2], 33); + + let v: Vec = m.keys().collect(); + assert_eq!(v, [k1, k2]); + } +} diff --git a/lib/cretonne/src/entity_map.rs b/lib/cretonne/src/entity_map.rs deleted file mode 100644 index 7afb863ed0..0000000000 --- a/lib/cretonne/src/entity_map.rs +++ /dev/null @@ -1,263 +0,0 @@ -//! Densely numbered entity references as mapping keys. -//! -//! The `EntityMap` data structure uses the dense index space to implement a map with a vector. -//! There are primary and secondary entity maps: -//! -//! - A *primary* `EntityMap` contains the main definition of an entity, and it can be used to -//! allocate new entity references with the `push` method. The values stores in a primary map -//! must implement the `PrimaryEntityData` marker trait. -//! - A *secondary* `EntityMap` contains additional data about entities kept in a primary map. The -//! values need to implement `Clone + Default` traits so the map can be grown with `ensure`. - -use entity::EntityRef; -use std::marker::PhantomData; -use std::ops::{Index, IndexMut}; - -/// A mapping `K -> V` for densely indexed entity references. -#[derive(Debug, Clone)] -pub struct EntityMap - where K: EntityRef -{ - elems: Vec, - unused: PhantomData, -} - -/// Shared `EntityMap` implementation for all value types. -impl EntityMap - where K: EntityRef -{ - /// Create a new empty map. - pub fn new() -> Self { - EntityMap { - elems: Vec::new(), - unused: PhantomData, - } - } - - /// Check if `k` is a valid key in the map. - pub fn is_valid(&self, k: K) -> bool { - k.index() < self.elems.len() - } - - /// Get the element at `k` if it exists. - pub fn get(&self, k: K) -> Option<&V> { - self.elems.get(k.index()) - } - - /// Is this map completely empty? - pub fn is_empty(&self) -> bool { - self.elems.is_empty() - } - - /// Remove all entries from this map. - pub fn clear(&mut self) { - self.elems.clear() - } - - /// Iterate over all the keys in this map. - pub fn keys(&self) -> Keys { - Keys { - pos: 0, - rev_pos: self.elems.len(), - unused: PhantomData, - } - } -} - -/// A marker trait for data stored in primary entity maps. -/// -/// A primary entity map can be used to allocate new entity references with the `push` method. It -/// is important that entity references can't be created anywhere else, so the data stored in a -/// primary entity map must be tagged as `PrimaryEntityData` to unlock the `push` method. -pub trait PrimaryEntityData {} - -/// Additional methods for primary entry maps only. -/// -/// These are identified by the `PrimaryEntityData` marker trait. -impl EntityMap - where K: EntityRef, - V: PrimaryEntityData -{ - /// Get the key that will be assigned to the next pushed value. - pub fn next_key(&self) -> K { - K::new(self.elems.len()) - } - - /// Append `v` to the mapping, assigning a new key which is returned. - pub fn push(&mut self, v: V) -> K { - let k = self.next_key(); - self.elems.push(v); - k - } - - /// Get the total number of entity references created. - pub fn len(&self) -> usize { - self.elems.len() - } -} - -/// Additional methods for value types that implement `Clone` and `Default`. -/// -/// When the value type implements these additional traits, the `EntityMap` can be resized -/// explicitly with the `ensure` method. -/// -/// Use this for secondary maps that are mapping keys created by another primary map. -impl EntityMap - where K: EntityRef, - V: Clone + Default -{ - /// Create a new secondary `EntityMap` that is prepared to hold `n` elements. - /// - /// Use this when the length of the primary map is known: - /// ``` - /// let secondary_map = EntityMap::with_capacity(primary_map.len()); - /// ``` - pub fn with_capacity(n: usize) -> Self { - let mut map = EntityMap { - elems: Vec::with_capacity(n), - unused: PhantomData, - }; - map.elems.resize(n, V::default()); - map - } - - /// Resize the map to have `n` entries by adding default entries as needed. - pub fn resize(&mut self, n: usize) { - self.elems.resize(n, V::default()); - } - - /// Ensure that `k` is a valid key but adding default entries if necessary. - /// - /// Return a mutable reference to the corresponding entry. - pub fn ensure(&mut self, k: K) -> &mut V { - if !self.is_valid(k) { - self.resize(k.index() + 1) - } - &mut self.elems[k.index()] - } - - /// Get the element at `k` or the default value if `k` is out of range. - pub fn get_or_default(&self, k: K) -> V { - self.elems.get(k.index()).cloned().unwrap_or_default() - } -} - -/// Immutable indexing into an `EntityMap`. -/// The indexed value must be in the map, either because it was created by `push`, or the key was -/// passed to `ensure`. -impl Index for EntityMap - where K: EntityRef -{ - type Output = V; - - fn index(&self, k: K) -> &V { - &self.elems[k.index()] - } -} - -/// Mutable indexing into an `EntityMap`. -/// Use `ensure` instead if the key is not known to be valid. -impl IndexMut for EntityMap - where K: EntityRef -{ - fn index_mut(&mut self, k: K) -> &mut V { - &mut self.elems[k.index()] - } -} - -/// Iterate over all keys in order. -pub struct Keys - where K: EntityRef -{ - pos: usize, - rev_pos: usize, - unused: PhantomData, -} - -impl Iterator for Keys - where K: EntityRef -{ - type Item = K; - - fn next(&mut self) -> Option { - if self.pos < self.rev_pos { - let k = K::new(self.pos); - self.pos += 1; - Some(k) - } else { - None - } - } -} - -impl DoubleEndedIterator for Keys - where K: EntityRef -{ - fn next_back(&mut self) -> Option { - if self.rev_pos > self.pos { - let k = K::new(self.rev_pos - 1); - self.rev_pos -= 1; - Some(k) - } else { - None - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - // `EntityRef` impl for testing. - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - struct E(u32); - - impl EntityRef for E { - fn new(i: usize) -> Self { - E(i as u32) - } - fn index(self) -> usize { - self.0 as usize - } - } - - impl PrimaryEntityData for isize {} - - #[test] - fn basic() { - let r0 = E(0); - let r1 = E(1); - let r2 = E(2); - let mut m = EntityMap::new(); - - let v: Vec = m.keys().collect(); - assert_eq!(v, []); - - assert!(!m.is_valid(r0)); - m.ensure(r2); - m[r2] = 3; - assert!(m.is_valid(r1)); - m[r1] = 5; - - assert_eq!(m[r1], 5); - assert_eq!(m[r2], 3); - - let v: Vec = m.keys().collect(); - assert_eq!(v, [r0, r1, r2]); - - let shared = &m; - assert_eq!(shared[r0], 0); - assert_eq!(shared[r1], 5); - assert_eq!(shared[r2], 3); - } - - #[test] - fn push() { - let mut m = EntityMap::new(); - let k1: E = m.push(12); - let k2 = m.push(33); - - assert_eq!(m[k1], 12); - assert_eq!(m[k2], 33); - } -} diff --git a/lib/cretonne/src/flowgraph.rs b/lib/cretonne/src/flowgraph.rs index f7cb0c9729..504d90fb9d 100644 --- a/lib/cretonne/src/flowgraph.rs +++ b/lib/cretonne/src/flowgraph.rs @@ -25,7 +25,7 @@ use ir::{Function, Inst, Ebb}; use ir::instructions::BranchInfo; -use entity_map::EntityMap; +use entity::EntityMap; use std::mem; /// A basic block denoted by its enclosing Ebb and last instruction. diff --git a/lib/cretonne/src/ir/dfg.rs b/lib/cretonne/src/ir/dfg.rs index 959b29c8e8..219557aeb8 100644 --- a/lib/cretonne/src/ir/dfg.rs +++ b/lib/cretonne/src/ir/dfg.rs @@ -1,6 +1,6 @@ //! Data flow graph tracking Instructions, Values, and EBBs. -use entity_map::{EntityMap, PrimaryEntityData}; +use entity::{PrimaryMap, EntityMap}; use isa::TargetIsa; use ir::builder::{InsertBuilder, ReplaceBuilder}; use ir::extfunc::ExtFuncData; @@ -27,7 +27,7 @@ pub struct DataFlowGraph { /// Data about all of the instructions in the function, including opcodes and operands. /// The instructions in this map are not in program order. That is tracked by `Layout`, along /// with the EBB containing each instruction. - insts: EntityMap, + insts: PrimaryMap, /// List of result values for each instruction. /// @@ -38,7 +38,7 @@ pub struct DataFlowGraph { /// Extended basic blocks in the function and their arguments. /// This map is not in program order. That is handled by `Layout`, and so is the sequence of /// instructions contained in each EBB. - ebbs: EntityMap, + ebbs: PrimaryMap, /// Memory pool of value lists. /// @@ -50,33 +50,27 @@ pub struct DataFlowGraph { pub value_lists: ValueListPool, /// Primary value table with entries for all values. - values: EntityMap, + values: PrimaryMap, /// Function signature table. These signatures are referenced by indirect call instructions as /// well as the external function references. - pub signatures: EntityMap, + pub signatures: PrimaryMap, /// External function references. These are functions that can be called directly. - pub ext_funcs: EntityMap, + pub ext_funcs: PrimaryMap, } -impl PrimaryEntityData for InstructionData {} -impl PrimaryEntityData for EbbData {} -impl PrimaryEntityData for ValueData {} -impl PrimaryEntityData for Signature {} -impl PrimaryEntityData for ExtFuncData {} - impl DataFlowGraph { /// Create a new empty `DataFlowGraph`. pub fn new() -> DataFlowGraph { DataFlowGraph { - insts: EntityMap::new(), + insts: PrimaryMap::new(), results: EntityMap::new(), - ebbs: EntityMap::new(), + ebbs: PrimaryMap::new(), value_lists: ValueListPool::new(), - values: EntityMap::new(), - signatures: EntityMap::new(), - ext_funcs: EntityMap::new(), + values: PrimaryMap::new(), + signatures: PrimaryMap::new(), + ext_funcs: PrimaryMap::new(), } } @@ -115,7 +109,7 @@ impl DataFlowGraph { /// Resolve value aliases. /// /// Find the original SSA value that `value` aliases. -fn resolve_aliases(values: &EntityMap, value: Value) -> Value { +fn resolve_aliases(values: &PrimaryMap, value: Value) -> Value { let mut v = value; // Note that values may be empty here. diff --git a/lib/cretonne/src/ir/function.rs b/lib/cretonne/src/ir/function.rs index 028c376479..c9d0031deb 100644 --- a/lib/cretonne/src/ir/function.rs +++ b/lib/cretonne/src/ir/function.rs @@ -3,9 +3,10 @@ //! The `Function` struct defined in this module owns all of its extended basic blocks and //! instructions. -use entity_map::{EntityMap, PrimaryEntityData}; -use ir::{FunctionName, CallConv, Signature, JumpTableData, GlobalVarData, DataFlowGraph, Layout}; -use ir::{JumpTables, InstEncodings, ValueLocations, StackSlots, GlobalVars, EbbOffsets}; +use entity::{PrimaryMap, EntityMap}; +use ir; +use ir::{FunctionName, CallConv, Signature, DataFlowGraph, Layout}; +use ir::{InstEncodings, ValueLocations, JumpTables, StackSlots, EbbOffsets}; use isa::TargetIsa; use std::fmt; use write::write_function; @@ -26,7 +27,7 @@ pub struct Function { pub stack_slots: StackSlots, /// Global variables referenced. - pub global_vars: GlobalVars, + pub global_vars: PrimaryMap, /// Jump tables used in this function. pub jump_tables: JumpTables, @@ -52,9 +53,6 @@ pub struct Function { pub offsets: EbbOffsets, } -impl PrimaryEntityData for JumpTableData {} -impl PrimaryEntityData for GlobalVarData {} - impl Function { /// Create a function with the given name and signature. pub fn with_name_signature(name: FunctionName, sig: Signature) -> Function { @@ -62,8 +60,8 @@ impl Function { name, signature: sig, stack_slots: StackSlots::new(), - global_vars: GlobalVars::new(), - jump_tables: EntityMap::new(), + global_vars: PrimaryMap::new(), + jump_tables: PrimaryMap::new(), dfg: DataFlowGraph::new(), layout: Layout::new(), encodings: EntityMap::new(), diff --git a/lib/cretonne/src/ir/layout.rs b/lib/cretonne/src/ir/layout.rs index 9e03daa8a9..ca54cefdb3 100644 --- a/lib/cretonne/src/ir/layout.rs +++ b/lib/cretonne/src/ir/layout.rs @@ -5,7 +5,7 @@ use std::cmp; use std::iter::{Iterator, IntoIterator}; -use entity_map::EntityMap; +use entity::EntityMap; use packed_option::PackedOption; use ir::{Ebb, Inst, Type, DataFlowGraph}; use ir::builder::InstInserterBase; @@ -278,7 +278,7 @@ impl Layout { impl Layout { /// Is `ebb` currently part of the layout? pub fn is_ebb_inserted(&self, ebb: Ebb) -> bool { - Some(ebb) == self.first_ebb || (self.ebbs.is_valid(ebb) && self.ebbs[ebb].prev.is_some()) + Some(ebb) == self.first_ebb || self.ebbs[ebb].prev.is_some() } /// Insert `ebb` as the last EBB in the layout. @@ -286,7 +286,7 @@ impl Layout { assert!(!self.is_ebb_inserted(ebb), "Cannot append EBB that is already in the layout"); { - let node = self.ebbs.ensure(ebb); + let node = &mut self.ebbs[ebb]; assert!(node.first_inst.is_none() && node.last_inst.is_none()); node.prev = self.last_ebb.into(); node.next = None.into(); @@ -308,7 +308,7 @@ impl Layout { "EBB Insertion point not in the layout"); let after = self.ebbs[before].prev; { - let node = self.ebbs.ensure(ebb); + let node = &mut self.ebbs[ebb]; node.next = before.into(); node.prev = after; } @@ -328,7 +328,7 @@ impl Layout { "EBB Insertion point not in the layout"); let before = self.ebbs[after].next; { - let node = self.ebbs.ensure(ebb); + let node = &mut self.ebbs[ebb]; node.next = before; node.prev = after.into(); } @@ -406,11 +406,7 @@ impl<'f> IntoIterator for &'f Layout { impl Layout { /// Get the EBB containing `inst`, or `None` if `inst` is not inserted in the layout. pub fn inst_ebb(&self, inst: Inst) -> Option { - if self.insts.is_valid(inst) { - self.insts[inst].ebb.into() - } else { - None - } + self.insts[inst].ebb.into() } /// Get the EBB containing the program point `pp`. Panic if `pp` is not in the layout. @@ -433,7 +429,7 @@ impl Layout { { let ebb_node = &mut self.ebbs[ebb]; { - let inst_node = self.insts.ensure(inst); + let inst_node = &mut self.insts[inst]; inst_node.ebb = ebb.into(); inst_node.prev = ebb_node.last_inst; assert!(inst_node.next.is_none()); @@ -465,7 +461,7 @@ impl Layout { .expect("Instruction before insertion point not in the layout"); let after = self.insts[before].prev; { - let inst_node = self.insts.ensure(inst); + let inst_node = &mut self.insts[inst]; inst_node.ebb = ebb.into(); inst_node.next = before.into(); inst_node.prev = after; @@ -543,7 +539,7 @@ impl Layout { let next_ebb = self.ebbs[old_ebb].next; let last_inst = self.ebbs[old_ebb].last_inst; { - let node = self.ebbs.ensure(new_ebb); + let node = &mut self.ebbs[new_ebb]; node.prev = old_ebb.into(); node.next = next_ebb; node.first_inst = before.into(); diff --git a/lib/cretonne/src/ir/mod.rs b/lib/cretonne/src/ir/mod.rs index 1e31e34010..75e68d110f 100644 --- a/lib/cretonne/src/ir/mod.rs +++ b/lib/cretonne/src/ir/mod.rs @@ -36,20 +36,17 @@ pub use ir::types::Type; pub use ir::valueloc::{ValueLoc, ArgumentLoc}; use binemit; -use entity_map::EntityMap; +use entity::{PrimaryMap, EntityMap}; use isa; /// Map of value locations. pub type ValueLocations = EntityMap; /// Map of jump tables. -pub type JumpTables = EntityMap; +pub type JumpTables = PrimaryMap; /// Map of instruction encodings. pub type InstEncodings = EntityMap; /// Code offsets for EBBs. pub type EbbOffsets = EntityMap; - -/// Map of global variables. -pub type GlobalVars = EntityMap; diff --git a/lib/cretonne/src/ir/stackslot.rs b/lib/cretonne/src/ir/stackslot.rs index 6f3de96cd2..528f6b22f2 100644 --- a/lib/cretonne/src/ir/stackslot.rs +++ b/lib/cretonne/src/ir/stackslot.rs @@ -3,7 +3,7 @@ //! The `StackSlotData` struct keeps track of a single stack slot in a function. //! -use entity_map::{EntityMap, PrimaryEntityData, Keys}; +use entity::{PrimaryMap, Keys}; use ir::{Type, StackSlot}; use std::fmt; use std::ops::Index; @@ -124,15 +124,13 @@ impl fmt::Display for StackSlotData { } } -impl PrimaryEntityData for StackSlotData {} - /// Stack frame manager. /// /// Keep track of all the stack slots used by a function. #[derive(Clone, Debug)] pub struct StackSlots { /// All allocated stack slots. - slots: EntityMap, + slots: PrimaryMap, /// All the outgoing stack slots, ordered by offset. outgoing: Vec, @@ -152,7 +150,7 @@ impl StackSlots { /// Create an empty stack slot manager. pub fn new() -> StackSlots { StackSlots { - slots: EntityMap::new(), + slots: PrimaryMap::new(), outgoing: Vec::new(), frame_size: None, } diff --git a/lib/cretonne/src/legalizer/boundary.rs b/lib/cretonne/src/legalizer/boundary.rs index 6977c9e7bc..71c79ef46b 100644 --- a/lib/cretonne/src/legalizer/boundary.rs +++ b/lib/cretonne/src/legalizer/boundary.rs @@ -585,7 +585,7 @@ fn spill_entry_arguments(func: &mut Function, entry: Ebb) { .zip(func.dfg.ebb_args(entry)) { if let ArgumentLoc::Stack(offset) = abi.location { let ss = func.stack_slots.make_incoming_arg(abi.value_type, offset); - *func.locations.ensure(arg) = ValueLoc::Stack(ss); + func.locations[arg] = ValueLoc::Stack(ss); } } } @@ -646,7 +646,7 @@ fn spill_call_arguments(dfg: &mut DataFlowGraph, // Insert the spill instructions and rewrite call arguments. for (idx, arg, ss) in arglist { let stack_val = dfg.ins(pos).spill(arg); - *locations.ensure(stack_val) = ValueLoc::Stack(ss); + locations[stack_val] = ValueLoc::Stack(ss); dfg.inst_variable_args_mut(inst)[idx] = stack_val; } diff --git a/lib/cretonne/src/legalizer/mod.rs b/lib/cretonne/src/legalizer/mod.rs index faed731c95..230c7adc7e 100644 --- a/lib/cretonne/src/legalizer/mod.rs +++ b/lib/cretonne/src/legalizer/mod.rs @@ -73,7 +73,7 @@ pub fn legalize_function(func: &mut ir::Function, match isa.encode(&pos.func.dfg, &pos.func.dfg[inst], pos.func.dfg.ctrl_typevar(inst)) { - Ok(encoding) => *pos.func.encodings.ensure(inst) = encoding, + Ok(encoding) => pos.func.encodings[inst] = encoding, Err(action) => { // We should transform the instruction into legal equivalents. let changed = action(inst, pos.func, cfg); diff --git a/lib/cretonne/src/lib.rs b/lib/cretonne/src/lib.rs index 324698c53c..6cb6687138 100644 --- a/lib/cretonne/src/lib.rs +++ b/lib/cretonne/src/lib.rs @@ -19,7 +19,6 @@ pub mod binemit; pub mod bitset; pub mod dominator_tree; pub mod entity_list; -pub mod entity_map; pub mod flowgraph; pub mod ir; pub mod isa; diff --git a/lib/cretonne/src/loop_analysis.rs b/lib/cretonne/src/loop_analysis.rs index 5a4607ba79..55ddf1f4df 100644 --- a/lib/cretonne/src/loop_analysis.rs +++ b/lib/cretonne/src/loop_analysis.rs @@ -2,7 +2,8 @@ //! and parent in the loop tree. use dominator_tree::DominatorTree; -use entity_map::{EntityMap, PrimaryEntityData, Keys}; +use entity::{PrimaryMap, Keys}; +use entity::EntityMap; use flowgraph::ControlFlowGraph; use ir::{Function, Ebb, Layout}; use packed_option::PackedOption; @@ -17,7 +18,7 @@ entity_impl!(Loop, "loop"); /// Loops are referenced by the Loop object, and for each loop you can access its header EBB, /// its eventual parent in the loop tree and all the EBB belonging to the loop. pub struct LoopAnalysis { - loops: EntityMap, + loops: PrimaryMap, ebb_loop_map: EntityMap>, } @@ -26,8 +27,6 @@ struct LoopData { parent: PackedOption, } -impl PrimaryEntityData for LoopData {} - impl LoopData { /// Creates a `LoopData` object with the loop header and its eventual parent in the loop tree. pub fn new(header: Ebb, parent: Option) -> LoopData { @@ -44,7 +43,7 @@ impl LoopAnalysis { /// a function. pub fn new() -> LoopAnalysis { LoopAnalysis { - loops: EntityMap::new(), + loops: PrimaryMap::new(), ebb_loop_map: EntityMap::new(), } } diff --git a/lib/cretonne/src/regalloc/coloring.rs b/lib/cretonne/src/regalloc/coloring.rs index 02e4d47f81..49f26fbd37 100644 --- a/lib/cretonne/src/regalloc/coloring.rs +++ b/lib/cretonne/src/regalloc/coloring.rs @@ -707,7 +707,7 @@ impl<'a> Context<'a> { self.divert.regmove(m.value, m.from, m.to); let inst = dfg.ins(pos).regmove(m.value, m.from, m.to); match self.isa.encode(dfg, &dfg[inst], ty) { - Ok(encoding) => *encodings.ensure(inst) = encoding, + Ok(encoding) => encodings[inst] = encoding, _ => panic!("Can't encode {} {}", m.rc, dfg.display_inst(inst, self.isa)), } } diff --git a/lib/cretonne/src/regalloc/diversion.rs b/lib/cretonne/src/regalloc/diversion.rs index bbc5c067ae..c7c9595972 100644 --- a/lib/cretonne/src/regalloc/diversion.rs +++ b/lib/cretonne/src/regalloc/diversion.rs @@ -7,7 +7,7 @@ //! These register diversions are local to an EBB. No values can be diverted when entering a new //! EBB. -use entity_map::EntityMap; +use entity::EntityMap; use ir::{Value, ValueLoc}; use isa::RegUnit; diff --git a/lib/cretonne/src/regalloc/spilling.rs b/lib/cretonne/src/regalloc/spilling.rs index 12a938c81c..35ef526993 100644 --- a/lib/cretonne/src/regalloc/spilling.rs +++ b/lib/cretonne/src/regalloc/spilling.rs @@ -453,7 +453,7 @@ impl<'a> Context<'a> { .make_spill_slot(self.cur.func.dfg.value_type(value)); for &v in self.virtregs.congruence_class(&value) { self.liveness.spill(v); - *self.cur.func.locations.ensure(v) = ValueLoc::Stack(ss); + self.cur.func.locations[v] = ValueLoc::Stack(ss); } } diff --git a/lib/cretonne/src/regalloc/virtregs.rs b/lib/cretonne/src/regalloc/virtregs.rs index 17fa641fcd..722de5a1f4 100644 --- a/lib/cretonne/src/regalloc/virtregs.rs +++ b/lib/cretonne/src/regalloc/virtregs.rs @@ -12,7 +12,7 @@ //! memory-to-memory copies when a spilled value is passed as an EBB argument. use entity_list::{EntityList, ListPool}; -use entity_map::{EntityMap, PrimaryEntityData, Keys}; +use entity::{PrimaryMap, EntityMap, Keys}; use ir::Value; use packed_option::PackedOption; use ref_slice::ref_slice; @@ -23,7 +23,6 @@ pub struct VirtReg(u32); entity_impl!(VirtReg, "vreg"); type ValueList = EntityList; -impl PrimaryEntityData for ValueList {} /// Collection of virtual registers. /// @@ -37,7 +36,7 @@ pub struct VirtRegs { /// /// The list of values ion a virtual register is kept sorted according to the dominator tree's /// RPO of the value defs. - vregs: EntityMap, + vregs: PrimaryMap, /// Each value belongs to at most one virtual register. value_vregs: EntityMap>, @@ -49,7 +48,7 @@ impl VirtRegs { pub fn new() -> VirtRegs { VirtRegs { pool: ListPool::new(), - vregs: EntityMap::new(), + vregs: PrimaryMap::new(), value_vregs: EntityMap::new(), } } @@ -63,7 +62,7 @@ impl VirtRegs { /// Get the virtual register containing `value`, if any. pub fn get(&self, value: Value) -> Option { - self.value_vregs.get_or_default(value).into() + self.value_vregs[value].into() } /// Get the list of values in `vreg`. The values are ordered according to `DomTree::rpo_cmp` of @@ -133,7 +132,7 @@ impl VirtRegs { self.vregs[vreg].extend(values.iter().cloned(), &mut self.pool); for &v in values { - *self.value_vregs.ensure(v) = vreg.into(); + self.value_vregs[v] = vreg.into(); } vreg diff --git a/lib/cretonne/src/sparse_map.rs b/lib/cretonne/src/sparse_map.rs index 84c17f7b5f..4918675d27 100644 --- a/lib/cretonne/src/sparse_map.rs +++ b/lib/cretonne/src/sparse_map.rs @@ -35,8 +35,7 @@ //! - `SparseMap` requires the values to implement `SparseMapValue` which means that they must //! contain their own key. -use entity_map::EntityMap; -use entity::EntityRef; +use entity::{EntityRef, EntityMap}; use std::mem; use std::slice; use std::u32; @@ -151,7 +150,7 @@ impl SparseMap let idx = self.dense.len(); assert!(idx <= u32::MAX as usize, "SparseMap overflow"); self.dense.push(value); - *self.sparse.ensure(key) = idx as u32; + self.sparse[key] = idx as u32; None } diff --git a/lib/cretonne/src/verifier/liveness.rs b/lib/cretonne/src/verifier/liveness.rs index 2dff4a6e3e..8b1ab47f4c 100644 --- a/lib/cretonne/src/verifier/liveness.rs +++ b/lib/cretonne/src/verifier/liveness.rs @@ -63,7 +63,7 @@ impl<'a> LivenessVerifier<'a> { fn check_insts(&self) -> Result { for ebb in self.func.layout.ebbs() { for inst in self.func.layout.ebb_insts(ebb) { - let encoding = self.func.encodings.get_or_default(inst); + let encoding = self.func.encodings[inst]; // Check the defs. for &val in self.func.dfg.inst_results(inst) { diff --git a/lib/cretonne/src/verifier/mod.rs b/lib/cretonne/src/verifier/mod.rs index 0995449362..15b5219334 100644 --- a/lib/cretonne/src/verifier/mod.rs +++ b/lib/cretonne/src/verifier/mod.rs @@ -688,7 +688,7 @@ impl<'a> Verifier<'a> { for (&arg, &abi) in args.iter().zip(expected_args) { // Value types have already been checked by `typecheck_variable_args_iterator()`. if let ArgumentLoc::Stack(offset) = abi.location { - let arg_loc = self.func.locations.get_or_default(arg); + let arg_loc = self.func.locations[arg]; if let ValueLoc::Stack(ss) = arg_loc { // Argument value is assigned to a stack slot as expected. self.verify_stack_slot(inst, ss)?; @@ -811,7 +811,7 @@ impl<'a> Verifier<'a> { None => return Ok(()), }; - let encoding = self.func.encodings.get_or_default(inst); + let encoding = self.func.encodings[inst]; if encoding.is_legal() { let verify_encoding = isa.encode(&self.func.dfg, diff --git a/lib/cretonne/src/write.rs b/lib/cretonne/src/write.rs index d0166a1063..9004546f32 100644 --- a/lib/cretonne/src/write.rs +++ b/lib/cretonne/src/write.rs @@ -194,7 +194,7 @@ fn write_instruction(w: &mut Write, if !func.locations.is_empty() { let regs = isa.register_info(); for &r in func.dfg.inst_results(inst) { - write!(s, ",{}", func.locations.get_or_default(r).display(®s))? + write!(s, ",{}", func.locations[r].display(®s))? } } write!(s, "]")?; diff --git a/lib/frontend/src/frontend.rs b/lib/frontend/src/frontend.rs index 935251e89e..57c0aaa9e0 100644 --- a/lib/frontend/src/frontend.rs +++ b/lib/frontend/src/frontend.rs @@ -6,8 +6,7 @@ use cretonne::ir::instructions::BranchInfo; use cretonne::ir::function::DisplayFunction; use cretonne::isa::TargetIsa; use ssa::{SSABuilder, SideEffects, Block}; -use cretonne::entity_map::{EntityMap, PrimaryEntityData}; -use cretonne::entity::EntityRef; +use cretonne::entity::{EntityRef, EntityMap}; use std::hash::Hash; /// Permanent structure used for translating into Cretonne IL. @@ -38,8 +37,6 @@ struct EbbData { user_arg_count: usize, } -impl PrimaryEntityData for EbbData {} - struct Position { ebb: Ebb, basic_block: Block, @@ -231,7 +228,7 @@ impl<'a, Variable> FunctionBuilder<'a, Variable> pub fn create_ebb(&mut self) -> Ebb { let ebb = self.func.dfg.make_ebb(); self.builder.ssa.declare_ebb_header_block(ebb); - *self.builder.ebbs.ensure(ebb) = EbbData { + self.builder.ebbs[ebb] = EbbData { filled: false, pristine: true, user_arg_count: 0, @@ -286,7 +283,7 @@ impl<'a, Variable> FunctionBuilder<'a, Variable> /// In order to use a variable in a `use_var`, you need to declare its type with this method. pub fn declare_var(&mut self, var: Variable, ty: Type) { - *self.builder.types.ensure(var) = ty; + self.builder.types[var] = ty; } /// Returns the Cretonne IL value corresponding to the utilization at the current program @@ -560,7 +557,7 @@ impl<'a, Variable> FunctionBuilder<'a, Variable> fn handle_ssa_side_effects(&mut self, side_effects: SideEffects) { for split_ebb in side_effects.split_ebbs_created { - self.builder.ebbs.ensure(split_ebb).filled = true + self.builder.ebbs[split_ebb].filled = true } for modified_ebb in side_effects.instructions_added_to_ebbs { self.builder.ebbs[modified_ebb].pristine = false diff --git a/lib/frontend/src/ssa.rs b/lib/frontend/src/ssa.rs index bad49c6264..54485629d7 100644 --- a/lib/frontend/src/ssa.rs +++ b/lib/frontend/src/ssa.rs @@ -9,8 +9,7 @@ use cretonne::ir::{Ebb, Value, Inst, Type, DataFlowGraph, JumpTables, Layout, Cu InstBuilder}; use cretonne::ir::instructions::BranchInfo; use std::hash::Hash; -use cretonne::entity_map::{EntityMap, PrimaryEntityData}; -use cretonne::entity::EntityRef; +use cretonne::entity::{EntityRef, PrimaryMap, EntityMap}; use cretonne::packed_option::PackedOption; use cretonne::packed_option::ReservedValue; use std::u32; @@ -41,7 +40,7 @@ pub struct SSABuilder variables: EntityMap>, // Records the position of the basic blocks and the list of values used but not defined in the // block. - blocks: EntityMap>, + blocks: PrimaryMap>, // Records the basic blocks at the beginning of the `Ebb`s. ebb_headers: EntityMap>, } @@ -66,7 +65,6 @@ enum BlockData { // The block is implicitely sealed at creation. EbbBody { predecessor: Block }, } -impl PrimaryEntityData for BlockData {} impl BlockData { fn add_predecessor(&mut self, pred: Block, inst: Inst) { @@ -135,7 +133,7 @@ impl SSABuilder pub fn new() -> SSABuilder { SSABuilder { variables: EntityMap::new(), - blocks: EntityMap::new(), + blocks: PrimaryMap::new(), ebb_headers: EntityMap::new(), } } @@ -193,7 +191,7 @@ impl SSABuilder /// The SSA value is passed as an argument because it should be created with /// `ir::DataFlowGraph::append_result`. pub fn def_var(&mut self, var: Variable, val: Value, block: Block) { - self.variables.ensure(var).insert(block, val); + self.variables[var].insert(block, val); } /// Declares a use of a variable in a given basic block. Returns the SSA value corresponding @@ -296,7 +294,7 @@ impl SSABuilder ebb: ebb, undef_variables: Vec::new(), })); - *self.ebb_headers.ensure(ebb) = block.into(); + self.ebb_headers[ebb] = block.into(); block } /// Gets the header block corresponding to an Ebb, panics if the Ebb or the header block diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index 0d96861b51..9ec7547c43 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -1388,7 +1388,7 @@ impl<'a> Parser<'a> { .expect("duplicate inst references created"); if let Some(encoding) = encoding { - *ctx.function.encodings.ensure(inst) = encoding; + ctx.function.encodings[inst] = encoding; } if results.len() != num_results { @@ -1421,7 +1421,7 @@ impl<'a> Parser<'a> { .inst_results(inst) .iter() .zip(result_locations) { - *ctx.function.locations.ensure(value) = loc; + ctx.function.locations[value] = loc; } }