From 605bda292565a77d701086dc83cb5b039aa9cc3c Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 16 Jun 2017 11:51:41 -0700 Subject: [PATCH] Add a stack frame manager. Use a new StackSlots struct to keep track of a function's stack slots instead of just an entity map. This let's us build more internal data structures for tracking the stack slots if necessary. Start by adding a make_spill_slot() function that will be used by the register allocator. --- lib/cretonne/src/ir/function.rs | 9 ++--- lib/cretonne/src/ir/mod.rs | 2 +- lib/cretonne/src/ir/stackslot.rs | 68 ++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/lib/cretonne/src/ir/function.rs b/lib/cretonne/src/ir/function.rs index 075ee7c6fd..3cb547fdff 100644 --- a/lib/cretonne/src/ir/function.rs +++ b/lib/cretonne/src/ir/function.rs @@ -5,8 +5,8 @@ use binemit::CodeOffset; use entity_map::{EntityMap, PrimaryEntityData}; -use ir::{FunctionName, Signature, Value, Inst, Ebb, StackSlot, StackSlotData, JumpTable, - JumpTableData, ValueLoc, DataFlowGraph, Layout}; +use ir::{FunctionName, Signature, Value, Inst, Ebb, StackSlots, JumpTable, JumpTableData, + ValueLoc, DataFlowGraph, Layout}; use isa::{TargetIsa, Encoding}; use std::fmt::{self, Display, Debug, Formatter}; use write::write_function; @@ -24,7 +24,7 @@ pub struct Function { pub signature: Signature, /// Stack slots allocated in this function. - pub stack_slots: EntityMap, + pub stack_slots: StackSlots, /// Jump tables used in this function. pub jump_tables: EntityMap, @@ -50,7 +50,6 @@ pub struct Function { pub offsets: EntityMap, } -impl PrimaryEntityData for StackSlotData {} impl PrimaryEntityData for JumpTableData {} impl Function { @@ -59,7 +58,7 @@ impl Function { Function { name, signature: sig, - stack_slots: EntityMap::new(), + stack_slots: StackSlots::new(), jump_tables: EntityMap::new(), dfg: DataFlowGraph::new(), layout: Layout::new(), diff --git a/lib/cretonne/src/ir/mod.rs b/lib/cretonne/src/ir/mod.rs index 56c972c429..de5e1515b6 100644 --- a/lib/cretonne/src/ir/mod.rs +++ b/lib/cretonne/src/ir/mod.rs @@ -22,7 +22,7 @@ pub use ir::extfunc::{Signature, ArgumentType, ArgumentExtension, ArgumentPurpos pub use ir::types::Type; pub use ir::entities::{Ebb, Inst, Value, StackSlot, JumpTable, FuncRef, SigRef}; pub use ir::instructions::{Opcode, InstructionData, VariableArgs, ValueList, ValueListPool}; -pub use ir::stackslot::{StackSlotKind, StackSlotData}; +pub use ir::stackslot::{StackSlots, StackSlotKind, StackSlotData}; pub use ir::jumptable::JumpTableData; pub use ir::valueloc::{ValueLoc, ArgumentLoc}; pub use ir::dfg::{DataFlowGraph, ValueDef}; diff --git a/lib/cretonne/src/ir/stackslot.rs b/lib/cretonne/src/ir/stackslot.rs index a205f6d410..a1a5f0cb94 100644 --- a/lib/cretonne/src/ir/stackslot.rs +++ b/lib/cretonne/src/ir/stackslot.rs @@ -3,7 +3,10 @@ //! The `StackSlotData` struct keeps track of a single stack slot in a function. //! +use entity_map::{EntityMap, PrimaryEntityData, Keys}; +use ir::{Type, StackSlot}; use std::fmt; +use std::ops::Index; use std::str::FromStr; /// The kind of a stack slot. @@ -81,6 +84,71 @@ 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 { + slots: EntityMap, +} + +/// Stack slot manager functions that behave mostly like an entity map. +impl StackSlots { + /// Create an empty stack slot manager. + pub fn new() -> StackSlots { + StackSlots { slots: EntityMap::new() } + } + + /// Clear out everything. + pub fn clear(&mut self) { + self.slots.clear(); + } + + /// Allocate a new stack slot. + /// + /// This function should be primarily used by the text format parser. There are more convenient + /// functions for creating specific kinds of stack slots below. + pub fn push(&mut self, data: StackSlotData) -> StackSlot { + self.slots.push(data) + } + + /// Check if `ss` is a valid stack slot reference. + pub fn is_valid(&self, ss: StackSlot) -> bool { + self.slots.is_valid(ss) + } + + /// Get an iterator over all the stack slot keys. + pub fn keys(&self) -> Keys { + self.slots.keys() + } + + /// Get a reference to the next stack slot that would be created by `push()`. + /// + /// This should just be used by the parser. + pub fn next_key(&self) -> StackSlot { + self.slots.next_key() + } +} + +/// Higher-level stack frame manipulation functions. +impl StackSlots { + /// Create a new spill slot for spilling values of type `ty`. + pub fn make_spill_slot(&mut self, ty: Type) -> StackSlot { + let bytes = (ty.bits() as u32 + 7) / 8; + self.push(StackSlotData::new(StackSlotKind::SpillSlot, bytes)) + } +} + +impl Index for StackSlots { + type Output = StackSlotData; + + fn index(&self, ss: StackSlot) -> &StackSlotData { + &self.slots[ss] + } +} + #[cfg(test)] mod tests { use ir::Function;