Use an EntityMap for stack slots.

Delete the StackSlots iterator and move the remaining StackSlotData into its
own module.
This commit is contained in:
Jakob Stoklund Olesen
2016-08-12 16:34:18 -07:00
parent b266c28767
commit f4258ae293
4 changed files with 63 additions and 108 deletions

View File

@@ -1,10 +1,11 @@
//! Representation of Cretonne IL functions. //! Representation of Cretonne IL functions.
pub mod entities;
pub mod types; pub mod types;
pub mod entities;
pub mod condcodes; pub mod condcodes;
pub mod immediates; pub mod immediates;
pub mod instructions; pub mod instructions;
pub mod stackslot;
pub mod jumptable; pub mod jumptable;
pub mod dfg; pub mod dfg;
pub mod layout; pub mod layout;
@@ -12,13 +13,13 @@ pub mod layout;
pub use ir::types::{Type, FunctionName, Signature}; pub use ir::types::{Type, FunctionName, Signature};
pub use ir::entities::{Ebb, Inst, Value, StackSlot, JumpTable}; pub use ir::entities::{Ebb, Inst, Value, StackSlot, JumpTable};
pub use ir::instructions::{Opcode, InstructionData}; pub use ir::instructions::{Opcode, InstructionData};
pub use ir::stackslot::StackSlotData;
pub use ir::jumptable::JumpTableData;
pub use ir::dfg::DataFlowGraph; pub use ir::dfg::DataFlowGraph;
pub use ir::layout::Layout; pub use ir::layout::Layout;
use ir::jumptable::JumpTableData; use std::fmt::{self, Debug, Formatter};
use std::fmt::{self, Debug, Display, Formatter}; use entity_map::{EntityMap, PrimaryEntityData};
use std::ops::Index;
use entity_map::{EntityRef, EntityMap, PrimaryEntityData};
/// A function. /// A function.
pub struct Function { pub struct Function {
@@ -29,7 +30,7 @@ pub struct Function {
signature: Signature, signature: Signature,
/// Stack slots allocated in this function. /// Stack slots allocated in this function.
stack_slots: Vec<StackSlotData>, pub stack_slots: EntityMap<StackSlot, StackSlotData>,
/// Jump tables used in this function. /// Jump tables used in this function.
pub jump_tables: EntityMap<JumpTable, JumpTableData>, pub jump_tables: EntityMap<JumpTable, JumpTableData>,
@@ -41,7 +42,7 @@ pub struct Function {
pub layout: Layout, pub layout: Layout,
} }
// Tag JumpTableData as a primary entity so jump_tables above . impl PrimaryEntityData for StackSlotData {}
impl PrimaryEntityData for JumpTableData {} impl PrimaryEntityData for JumpTableData {}
impl Function { impl Function {
@@ -50,7 +51,7 @@ impl Function {
Function { Function {
name: name, name: name,
signature: sig, signature: sig,
stack_slots: Vec::new(), stack_slots: EntityMap::new(),
jump_tables: EntityMap::new(), jump_tables: EntityMap::new(),
dfg: DataFlowGraph::new(), dfg: DataFlowGraph::new(),
layout: Layout::new(), layout: Layout::new(),
@@ -66,23 +67,6 @@ impl Function {
pub fn own_signature(&self) -> &Signature { pub fn own_signature(&self) -> &Signature {
&self.signature &self.signature
} }
// Stack slots.
/// Allocate a new stack slot.
pub fn make_stack_slot(&mut self, data: StackSlotData) -> StackSlot {
let ss = StackSlot::new(self.stack_slots.len());
self.stack_slots.push(data);
ss
}
/// Iterate over all stack slots in function.
pub fn stack_slot_iter(&self) -> StackSlotIter {
StackSlotIter {
cur: 0,
end: self.stack_slots.len(),
}
}
} }
impl Debug for Function { impl Debug for Function {
@@ -91,76 +75,3 @@ impl Debug for Function {
fmt.write_str(&function_to_string(self)) fmt.write_str(&function_to_string(self))
} }
} }
// ====--------------------------------------------------------------------------------------====//
//
// Stack slot implementation.
//
// ====--------------------------------------------------------------------------------------====//
/// Contents of a stack slot.
#[derive(Debug)]
pub struct StackSlotData {
/// Size of stack slot in bytes.
pub size: u32,
}
impl StackSlotData {
/// Create a stack slot with the specified byte size.
pub fn new(size: u32) -> StackSlotData {
StackSlotData { size: size }
}
}
impl Display for StackSlotData {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(fmt, "stack_slot {}", self.size)
}
}
/// Allow immutable access to stack slots via function indexing.
impl Index<StackSlot> for Function {
type Output = StackSlotData;
fn index<'a>(&'a self, ss: StackSlot) -> &'a StackSlotData {
&self.stack_slots[ss.index()]
}
}
/// Stack slot iterator visits all stack slots in a function, returning `StackSlot` references.
pub struct StackSlotIter {
cur: usize,
end: usize,
}
impl Iterator for StackSlotIter {
type Item = StackSlot;
fn next(&mut self) -> Option<Self::Item> {
if self.cur < self.end {
let ss = StackSlot::new(self.cur);
self.cur += 1;
Some(ss)
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stack_slot() {
let mut func = Function::new();
let ss0 = func.make_stack_slot(StackSlotData::new(4));
let ss1 = func.make_stack_slot(StackSlotData::new(8));
assert_eq!(ss0.to_string(), "ss0");
assert_eq!(ss1.to_string(), "ss1");
assert_eq!(func[ss0].size, 4);
assert_eq!(func[ss1].size, 8);
}
}

View File

@@ -0,0 +1,45 @@
//! Stack slots.
//!
//! The `StackSlotData` struct keeps track of a single stack slot in a function.
//!
use std::fmt::{self, Display, Formatter};
/// Contents of a stack slot.
#[derive(Debug)]
pub struct StackSlotData {
/// Size of stack slot in bytes.
pub size: u32,
}
impl StackSlotData {
/// Create a stack slot with the specified byte size.
pub fn new(size: u32) -> StackSlotData {
StackSlotData { size: size }
}
}
impl Display for StackSlotData {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(fmt, "stack_slot {}", self.size)
}
}
#[cfg(test)]
mod tests {
use ir::Function;
use super::StackSlotData;
#[test]
fn stack_slot() {
let mut func = Function::new();
let ss0 = func.stack_slots.push(StackSlotData::new(4));
let ss1 = func.stack_slots.push(StackSlotData::new(8));
assert_eq!(ss0.to_string(), "ss0");
assert_eq!(ss1.to_string(), "ss1");
assert_eq!(func.stack_slots[ss0].size, 4);
assert_eq!(func.stack_slots[ss1].size, 8);
}
}

View File

@@ -68,9 +68,9 @@ fn write_spec(w: &mut Write, func: &Function) -> Result {
fn write_preamble(w: &mut Write, func: &Function) -> io::Result<bool> { fn write_preamble(w: &mut Write, func: &Function) -> io::Result<bool> {
let mut any = false; let mut any = false;
for ss in func.stack_slot_iter() { for ss in func.stack_slots.keys() {
any = true; any = true;
try!(writeln!(w, " {} = {}", ss, func[ss])); try!(writeln!(w, " {} = {}", ss, func.stack_slots[ss]));
} }
for jt in func.jump_tables.keys() { for jt in func.jump_tables.keys() {
@@ -249,7 +249,7 @@ mod tests {
f.name.push_str("foo"); f.name.push_str("foo");
assert_eq!(function_to_string(&f), "function foo() {\n}\n"); assert_eq!(function_to_string(&f), "function foo() {\n}\n");
f.make_stack_slot(StackSlotData::new(4)); f.stack_slots.push(StackSlotData::new(4));
assert_eq!(function_to_string(&f), assert_eq!(function_to_string(&f),
"function foo() {\n ss0 = stack_slot 4\n}\n"); "function foo() {\n ss0 = stack_slot 4\n}\n");

View File

@@ -11,14 +11,13 @@ use std::fmt::{self, Display, Formatter};
use std::str::FromStr; use std::str::FromStr;
use std::u32; use std::u32;
use lexer::{self, Lexer, Token}; use lexer::{self, Lexer, Token};
use cretonne::ir::{Function, Ebb, Inst, Opcode, Value, Type, FunctionName, StackSlotData, use cretonne::ir::{Function, Ebb, Inst, Opcode, Value, Type, FunctionName, StackSlot,
JumpTable, StackSlot}; StackSlotData, JumpTable, JumpTableData};
use cretonne::ir::types::{VOID, Signature, ArgumentType, ArgumentExtension}; use cretonne::ir::types::{VOID, Signature, ArgumentType, ArgumentExtension};
use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64};
use cretonne::ir::entities::{NO_EBB, NO_VALUE}; use cretonne::ir::entities::{NO_EBB, NO_VALUE};
use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs, JumpData, use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs, JumpData,
BranchData, ReturnData}; BranchData, ReturnData};
use cretonne::ir::jumptable::JumpTableData;
pub use lexer::Location; pub use lexer::Location;
@@ -95,7 +94,7 @@ impl Context {
// Allocate a new stack slot and add a mapping number -> StackSlot. // Allocate a new stack slot and add a mapping number -> StackSlot.
fn add_ss(&mut self, number: u32, data: StackSlotData, loc: &Location) -> Result<()> { fn add_ss(&mut self, number: u32, data: StackSlotData, loc: &Location) -> Result<()> {
if self.stack_slots.insert(number, self.function.make_stack_slot(data)).is_some() { if self.stack_slots.insert(number, self.function.stack_slots.push(data)).is_some() {
err!(loc, "duplicate stack slot: ss{}", number) err!(loc, "duplicate stack slot: ss{}", number)
} else { } else {
Ok(()) Ok(())
@@ -1173,13 +1172,13 @@ mod tests {
.parse_function() .parse_function()
.unwrap(); .unwrap();
assert_eq!(func.name, "foo"); assert_eq!(func.name, "foo");
let mut iter = func.stack_slot_iter(); let mut iter = func.stack_slots.keys();
let ss0 = iter.next().unwrap(); let ss0 = iter.next().unwrap();
assert_eq!(ss0.to_string(), "ss0"); assert_eq!(ss0.to_string(), "ss0");
assert_eq!(func[ss0].size, 13); assert_eq!(func.stack_slots[ss0].size, 13);
let ss1 = iter.next().unwrap(); let ss1 = iter.next().unwrap();
assert_eq!(ss1.to_string(), "ss1"); assert_eq!(ss1.to_string(), "ss1");
assert_eq!(func[ss1].size, 1); assert_eq!(func.stack_slots[ss1].size, 1);
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
// Catch duplicate definitions. // Catch duplicate definitions.