cranelift_codegen/ir/
stackslot.rs

1//! Stack slots.
2//!
3//! The `StackSlotData` struct keeps track of a single stack slot in a function.
4//!
5
6use crate::entity::PrimaryMap;
7use crate::ir::entities::{DynamicStackSlot, DynamicType};
8use crate::ir::StackSlot;
9use core::fmt;
10use core::str::FromStr;
11
12/// imports only needed for testing.
13#[allow(unused_imports)]
14use crate::ir::{DynamicTypeData, GlobalValueData};
15
16#[allow(unused_imports)]
17use crate::ir::types::*;
18
19#[cfg(feature = "enable-serde")]
20use serde_derive::{Deserialize, Serialize};
21
22/// The size of an object on the stack, or the size of a stack frame.
23///
24/// We don't use `usize` to represent object sizes on the target platform because Cranelift supports
25/// cross-compilation, and `usize` is a type that depends on the host platform, not the target
26/// platform.
27pub type StackSize = u32;
28
29/// The kind of a stack slot.
30#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
31#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
32pub enum StackSlotKind {
33    /// An explicit stack slot. This is a chunk of stack memory for use by the `stack_load`
34    /// and `stack_store` instructions.
35    ExplicitSlot,
36    /// An explicit stack slot for dynamic vector types. This is a chunk of stack memory
37    /// for use by the `dynamic_stack_load` and `dynamic_stack_store` instructions.
38    ExplicitDynamicSlot,
39}
40
41impl FromStr for StackSlotKind {
42    type Err = ();
43
44    fn from_str(s: &str) -> Result<Self, ()> {
45        use self::StackSlotKind::*;
46        match s {
47            "explicit_slot" => Ok(ExplicitSlot),
48            "explicit_dynamic_slot" => Ok(ExplicitDynamicSlot),
49            _ => Err(()),
50        }
51    }
52}
53
54impl fmt::Display for StackSlotKind {
55    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56        use self::StackSlotKind::*;
57        f.write_str(match *self {
58            ExplicitSlot => "explicit_slot",
59            ExplicitDynamicSlot => "explicit_dynamic_slot",
60        })
61    }
62}
63
64/// Contents of a stack slot.
65#[derive(Clone, Debug, PartialEq, Eq, Hash)]
66#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
67pub struct StackSlotData {
68    /// The kind of stack slot.
69    pub kind: StackSlotKind,
70
71    /// Size of stack slot in bytes.
72    pub size: StackSize,
73
74    /// Alignment of stack slot as a power-of-two exponent (log2
75    /// value). The stack slot will be at least this aligned; it may
76    /// be aligned according to other considerations, such as minimum
77    /// stack slot size or machine word size, as well.
78    pub align_shift: u8,
79}
80
81impl StackSlotData {
82    /// Create a stack slot with the specified byte size and alignment.
83    pub fn new(kind: StackSlotKind, size: StackSize, align_shift: u8) -> Self {
84        Self {
85            kind,
86            size,
87            align_shift,
88        }
89    }
90}
91
92impl fmt::Display for StackSlotData {
93    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94        if self.align_shift != 0 {
95            write!(
96                f,
97                "{} {}, align = {}",
98                self.kind,
99                self.size,
100                1u32 << self.align_shift
101            )
102        } else {
103            write!(f, "{} {}", self.kind, self.size)
104        }
105    }
106}
107
108/// Contents of a dynamic stack slot.
109#[derive(Clone, Debug, PartialEq, Eq, Hash)]
110#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
111pub struct DynamicStackSlotData {
112    /// The kind of stack slot.
113    pub kind: StackSlotKind,
114
115    /// The type of this slot.
116    pub dyn_ty: DynamicType,
117}
118
119impl DynamicStackSlotData {
120    /// Create a stack slot with the specified byte size.
121    pub fn new(kind: StackSlotKind, dyn_ty: DynamicType) -> Self {
122        assert!(kind == StackSlotKind::ExplicitDynamicSlot);
123        Self { kind, dyn_ty }
124    }
125
126    /// Get the alignment in bytes of this stack slot given the stack pointer alignment.
127    pub fn alignment(&self, max_align: StackSize) -> StackSize {
128        debug_assert!(max_align.is_power_of_two());
129        max_align
130    }
131}
132
133impl fmt::Display for DynamicStackSlotData {
134    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135        write!(f, "{} {}", self.kind, self.dyn_ty)
136    }
137}
138
139/// All allocated stack slots.
140pub type StackSlots = PrimaryMap<StackSlot, StackSlotData>;
141
142/// All allocated dynamic stack slots.
143pub type DynamicStackSlots = PrimaryMap<DynamicStackSlot, DynamicStackSlotData>;
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148    use crate::ir::Function;
149    use alloc::string::ToString;
150
151    #[test]
152    fn stack_slot() {
153        let mut func = Function::new();
154
155        let ss0 =
156            func.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4, 0));
157        let ss1 =
158            func.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 8, 0));
159        assert_eq!(ss0.to_string(), "ss0");
160        assert_eq!(ss1.to_string(), "ss1");
161
162        assert_eq!(func.sized_stack_slots[ss0].size, 4);
163        assert_eq!(func.sized_stack_slots[ss1].size, 8);
164
165        assert_eq!(func.sized_stack_slots[ss0].to_string(), "explicit_slot 4");
166        assert_eq!(func.sized_stack_slots[ss1].to_string(), "explicit_slot 8");
167    }
168
169    #[test]
170    fn dynamic_stack_slot() {
171        let mut func = Function::new();
172
173        let int_vector_ty = I32X4;
174        let fp_vector_ty = F64X2;
175        let scale0 = GlobalValueData::DynScaleTargetConst {
176            vector_type: int_vector_ty,
177        };
178        let scale1 = GlobalValueData::DynScaleTargetConst {
179            vector_type: fp_vector_ty,
180        };
181        let gv0 = func.create_global_value(scale0);
182        let gv1 = func.create_global_value(scale1);
183        let dtd0 = DynamicTypeData::new(int_vector_ty, gv0);
184        let dtd1 = DynamicTypeData::new(fp_vector_ty, gv1);
185        let dt0 = func.dfg.make_dynamic_ty(dtd0);
186        let dt1 = func.dfg.make_dynamic_ty(dtd1);
187
188        let dss0 = func.create_dynamic_stack_slot(DynamicStackSlotData::new(
189            StackSlotKind::ExplicitDynamicSlot,
190            dt0,
191        ));
192        let dss1 = func.create_dynamic_stack_slot(DynamicStackSlotData::new(
193            StackSlotKind::ExplicitDynamicSlot,
194            dt1,
195        ));
196        assert_eq!(dss0.to_string(), "dss0");
197        assert_eq!(dss1.to_string(), "dss1");
198
199        assert_eq!(
200            func.dynamic_stack_slots[dss0].to_string(),
201            "explicit_dynamic_slot dt0"
202        );
203        assert_eq!(
204            func.dynamic_stack_slots[dss1].to_string(),
205            "explicit_dynamic_slot dt1"
206        );
207    }
208}