Split EntityMap into entity::PrimaryMap and entity::EntityMap.

The new PrimaryMap replaces the primary EntityMap and the PrimaryEntityData
marker trait which was causing some confusion. We now have a clear
division between the two types of maps:

- PrimaryMap is used to assign entity numbers to the primary data for an
  entity.
- EntityMap is a secondary mapping adding additional info.

The split also means that the secondary EntityMap can now behave as if
all keys have a default value. This means that we can get rid of the
annoying ensure() and get_or_default() methods ther were used everywhere
instead of indexing. Just use normal indexing now; non-existent keys
will return the default value.
This commit is contained in:
Jakob Stoklund Olesen
2017-08-18 15:04:10 -07:00
parent 8599372098
commit 7e08b14cf6
30 changed files with 413 additions and 363 deletions

View File

@@ -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() {

View File

@@ -67,7 +67,7 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> Result<CodeOffset
}
while let Some(inst) = cur.next_inst() {
let enc = cur.func.encodings.get_or_default(inst);
let enc = cur.func.encodings[inst];
let size = encinfo.bytes(enc);
// See if this might be a branch that is out of range.

View File

@@ -157,7 +157,7 @@ impl<'c, 'f> 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)),
}

View File

@@ -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(),
};

View File

@@ -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<K: EntityRef> {
pos: usize,
rev_pos: usize,
unused: PhantomData<K>,
}
impl<K: EntityRef> Keys<K> {
/// Create a `Keys` iterator that visits `count` entities starting from 0.
pub fn new(count: usize) -> Keys<K> {
Keys {
pos: 0,
rev_pos: count,
unused: PhantomData,
}
}
}
impl<K: EntityRef> Iterator for Keys<K> {
type Item = K;
fn next(&mut self) -> Option<Self::Item> {
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<usize>) {
let size = self.rev_pos - self.pos;
(size, Some(size))
}
}
impl<K: EntityRef> DoubleEndedIterator for Keys<K> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.rev_pos > self.pos {
let k = K::new(self.rev_pos - 1);
self.rev_pos -= 1;
Some(k)
} else {
None
}
}
}
impl<K: EntityRef> ExactSizeIterator for Keys<K> {}

View File

@@ -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<K, V>
where K: EntityRef,
V: Clone
{
elems: Vec<V>,
default: V,
unused: PhantomData<K>,
}
/// Shared `EntityMap` implementation for all value types.
impl<K, V> EntityMap<K, V>
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<K> {
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<K, V> Index<K> for EntityMap<K, V>
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<K, V> IndexMut<K> for EntityMap<K, V>
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<E> = 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<E> = 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);
}
}

View File

@@ -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 {

View File

@@ -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<K, V>
where K: EntityRef
{
elems: Vec<V>,
unused: PhantomData<K>,
}
impl<K, V> PrimaryMap<K, V>
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<K> {
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<K, V> Index<K> for PrimaryMap<K, V>
where K: EntityRef
{
type Output = V;
fn index(&self, k: K) -> &V {
&self.elems[k.index()]
}
}
/// Mutable indexing into an `PrimaryMap`.
impl<K, V> IndexMut<K> for PrimaryMap<K, V>
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::<E, isize>::new();
let v: Vec<E> = 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<E> = m.keys().collect();
assert_eq!(v, [k1, k2]);
}
}

View File

@@ -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<K, V>
where K: EntityRef
{
elems: Vec<V>,
unused: PhantomData<K>,
}
/// Shared `EntityMap` implementation for all value types.
impl<K, V> EntityMap<K, V>
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<K> {
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<K, V> EntityMap<K, V>
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<K, V> EntityMap<K, V>
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<K, V> Index<K> for EntityMap<K, V>
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<K, V> IndexMut<K> for EntityMap<K, V>
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<K>
where K: EntityRef
{
pos: usize,
rev_pos: usize,
unused: PhantomData<K>,
}
impl<K> Iterator for Keys<K>
where K: EntityRef
{
type Item = K;
fn next(&mut self) -> Option<Self::Item> {
if self.pos < self.rev_pos {
let k = K::new(self.pos);
self.pos += 1;
Some(k)
} else {
None
}
}
}
impl<K> DoubleEndedIterator for Keys<K>
where K: EntityRef
{
fn next_back(&mut self) -> Option<Self::Item> {
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<E> = 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<E> = 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);
}
}

View File

@@ -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.

View File

@@ -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<Inst, InstructionData>,
insts: PrimaryMap<Inst, InstructionData>,
/// 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<Ebb, EbbData>,
ebbs: PrimaryMap<Ebb, EbbData>,
/// 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<Value, ValueData>,
values: PrimaryMap<Value, ValueData>,
/// Function signature table. These signatures are referenced by indirect call instructions as
/// well as the external function references.
pub signatures: EntityMap<SigRef, Signature>,
pub signatures: PrimaryMap<SigRef, Signature>,
/// External function references. These are functions that can be called directly.
pub ext_funcs: EntityMap<FuncRef, ExtFuncData>,
pub ext_funcs: PrimaryMap<FuncRef, ExtFuncData>,
}
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, ValueData>, value: Value) -> Value {
fn resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Value {
let mut v = value;
// Note that values may be empty here.

View File

@@ -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<ir::GlobalVar, ir::GlobalVarData>,
/// 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(),

View File

@@ -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<Ebb> {
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();

View File

@@ -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<Value, ValueLoc>;
/// Map of jump tables.
pub type JumpTables = EntityMap<JumpTable, JumpTableData>;
pub type JumpTables = PrimaryMap<JumpTable, JumpTableData>;
/// Map of instruction encodings.
pub type InstEncodings = EntityMap<Inst, isa::Encoding>;
/// Code offsets for EBBs.
pub type EbbOffsets = EntityMap<Ebb, binemit::CodeOffset>;
/// Map of global variables.
pub type GlobalVars = EntityMap<GlobalVar, GlobalVarData>;

View File

@@ -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<StackSlot, StackSlotData>,
slots: PrimaryMap<StackSlot, StackSlotData>,
/// All the outgoing stack slots, ordered by offset.
outgoing: Vec<StackSlot>,
@@ -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,
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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<Loop, LoopData>,
loops: PrimaryMap<Loop, LoopData>,
ebb_loop_map: EntityMap<Ebb, PackedOption<Loop>>,
}
@@ -26,8 +27,6 @@ struct LoopData {
parent: PackedOption<Loop>,
}
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<Loop>) -> 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(),
}
}

View File

@@ -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)),
}
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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<Value>;
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<VirtReg, ValueList>,
vregs: PrimaryMap<VirtReg, ValueList>,
/// Each value belongs to at most one virtual register.
value_vregs: EntityMap<Value, PackedOption<VirtReg>>,
@@ -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<VirtReg> {
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

View File

@@ -35,8 +35,7 @@
//! - `SparseMap` requires the values to implement `SparseMapValue<K>` 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<K, V> SparseMap<K, V>
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
}

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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(&regs))?
write!(s, ",{}", func.locations[r].display(&regs))?
}
}
write!(s, "]")?;

View File

@@ -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

View File

@@ -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<Variable>
variables: EntityMap<Variable, HashMap<Block, Value>>,
// Records the position of the basic blocks and the list of values used but not defined in the
// block.
blocks: EntityMap<Block, BlockData<Variable>>,
blocks: PrimaryMap<Block, BlockData<Variable>>,
// Records the basic blocks at the beginning of the `Ebb`s.
ebb_headers: EntityMap<Ebb, PackedOption<Block>>,
}
@@ -66,7 +65,6 @@ enum BlockData<Variable> {
// The block is implicitely sealed at creation.
EbbBody { predecessor: Block },
}
impl<Variable> PrimaryEntityData for BlockData<Variable> {}
impl<Variable> BlockData<Variable> {
fn add_predecessor(&mut self, pred: Block, inst: Inst) {
@@ -135,7 +133,7 @@ impl<Variable> SSABuilder<Variable>
pub fn new() -> SSABuilder<Variable> {
SSABuilder {
variables: EntityMap::new(),
blocks: EntityMap::new(),
blocks: PrimaryMap::new(),
ebb_headers: EntityMap::new(),
}
}
@@ -193,7 +191,7 @@ impl<Variable> SSABuilder<Variable>
/// 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<Variable> SSABuilder<Variable>
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

View File

@@ -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;
}
}