/rust/registry/src/index.crates.io-1949cf8c6b5b557f/cranelift-codegen-0.129.1/src/ir/stackslot.rs
Line | Count | Source |
1 | | //! Stack slots. |
2 | | //! |
3 | | //! The `StackSlotData` struct keeps track of a single stack slot in a function. |
4 | | //! |
5 | | |
6 | | use crate::entity::PrimaryMap; |
7 | | use crate::ir::StackSlot; |
8 | | use crate::ir::entities::{DynamicStackSlot, DynamicType}; |
9 | | use core::fmt; |
10 | | use core::str::FromStr; |
11 | | |
12 | | #[cfg(feature = "enable-serde")] |
13 | | use serde_derive::{Deserialize, Serialize}; |
14 | | |
15 | | /// The size of an object on the stack, or the size of a stack frame. |
16 | | /// |
17 | | /// We don't use `usize` to represent object sizes on the target platform because Cranelift supports |
18 | | /// cross-compilation, and `usize` is a type that depends on the host platform, not the target |
19 | | /// platform. |
20 | | pub type StackSize = u32; |
21 | | |
22 | | /// The kind of a stack slot. |
23 | | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
24 | | #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] |
25 | | pub enum StackSlotKind { |
26 | | /// An explicit stack slot. This is a chunk of stack memory for use by the `stack_load` |
27 | | /// and `stack_store` instructions. |
28 | | ExplicitSlot, |
29 | | /// An explicit stack slot for dynamic vector types. This is a chunk of stack memory |
30 | | /// for use by the `dynamic_stack_load` and `dynamic_stack_store` instructions. |
31 | | ExplicitDynamicSlot, |
32 | | } |
33 | | |
34 | | impl FromStr for StackSlotKind { |
35 | | type Err = (); |
36 | | |
37 | 0 | fn from_str(s: &str) -> Result<Self, ()> { |
38 | | use self::StackSlotKind::*; |
39 | 0 | match s { |
40 | 0 | "explicit_slot" => Ok(ExplicitSlot), |
41 | 0 | "explicit_dynamic_slot" => Ok(ExplicitDynamicSlot), |
42 | 0 | _ => Err(()), |
43 | | } |
44 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotKind as core::str::traits::FromStr>::from_str Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotKind as core::str::traits::FromStr>::from_str |
45 | | } |
46 | | |
47 | | impl fmt::Display for StackSlotKind { |
48 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
49 | | use self::StackSlotKind::*; |
50 | 0 | f.write_str(match *self { |
51 | 0 | ExplicitSlot => "explicit_slot", |
52 | 0 | ExplicitDynamicSlot => "explicit_dynamic_slot", |
53 | | }) |
54 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotKind as core::fmt::Display>::fmt Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotKind as core::fmt::Display>::fmt |
55 | | } |
56 | | |
57 | | /// Contents of a stack slot. |
58 | | #[derive(Clone, Debug, PartialEq, Eq, Hash)] |
59 | | #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] |
60 | | pub struct StackSlotData { |
61 | | /// The kind of stack slot. |
62 | | pub kind: StackSlotKind, |
63 | | |
64 | | /// Size of stack slot in bytes. |
65 | | pub size: StackSize, |
66 | | |
67 | | /// Alignment of stack slot as a power-of-two exponent (log2 |
68 | | /// value). The stack slot will be at least this aligned; it may |
69 | | /// be aligned according to other considerations, such as minimum |
70 | | /// stack slot size or machine word size, as well. |
71 | | pub align_shift: u8, |
72 | | |
73 | | /// Opaque stackslot metadata handle, passed through to |
74 | | /// compilation result metadata describing stackslot location. |
75 | | /// |
76 | | /// In the face of compiler transforms like inlining that may move |
77 | | /// stackslots between functions, when an embedder wants to |
78 | | /// externally observe stackslots, it needs a first-class way for |
79 | | /// the identity of stackslots to be carried along with the IR |
80 | | /// entities. This opaque `StackSlotKey` allows the embedder to do |
81 | | /// so. |
82 | | pub key: Option<StackSlotKey>, |
83 | | } |
84 | | |
85 | | /// An opaque key uniquely identifying a stack slot. |
86 | | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
87 | | #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] |
88 | | pub struct StackSlotKey(u64); |
89 | | impl StackSlotKey { |
90 | | /// Construct a [`StackSlotKey`] from raw bits. |
91 | | /// |
92 | | /// An embedder can use any 64-bit value to describe a stack slot; |
93 | | /// there are no restrictions, and the value does not mean |
94 | | /// anything to Cranelift itself. |
95 | 0 | pub fn new(value: u64) -> StackSlotKey { |
96 | 0 | StackSlotKey(value) |
97 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotKey>::new Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotKey>::new |
98 | | |
99 | | /// Get the raw bits from the [`StackSlotKey`]. |
100 | 0 | pub fn bits(&self) -> u64 { |
101 | 0 | self.0 |
102 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotKey>::bits Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotKey>::bits |
103 | | } |
104 | | |
105 | | impl StackSlotData { |
106 | | /// Create a stack slot with the specified byte size and alignment. |
107 | 0 | pub fn new(kind: StackSlotKind, size: StackSize, align_shift: u8) -> Self { |
108 | 0 | Self { |
109 | 0 | kind, |
110 | 0 | size, |
111 | 0 | align_shift, |
112 | 0 | key: None, |
113 | 0 | } |
114 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotData>::new Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotData>::new |
115 | | |
116 | | /// Create a stack slot with the specified byte size and alignment |
117 | | /// and the given user-defined key. |
118 | 0 | pub fn new_with_key( |
119 | 0 | kind: StackSlotKind, |
120 | 0 | size: StackSize, |
121 | 0 | align_shift: u8, |
122 | 0 | key: StackSlotKey, |
123 | 0 | ) -> Self { |
124 | 0 | Self { |
125 | 0 | kind, |
126 | 0 | size, |
127 | 0 | align_shift, |
128 | 0 | key: Some(key), |
129 | 0 | } |
130 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotData>::new_with_key Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotData>::new_with_key |
131 | | } |
132 | | |
133 | | impl fmt::Display for StackSlotData { |
134 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
135 | 0 | let align_shift = if self.align_shift != 0 { |
136 | 0 | format!(", align = {}", 1u32 << self.align_shift) |
137 | | } else { |
138 | 0 | "".into() |
139 | | }; |
140 | 0 | let key = match self.key { |
141 | 0 | Some(value) => format!(", key = {}", value.bits()), |
142 | 0 | None => "".into(), |
143 | | }; |
144 | | |
145 | 0 | write!(f, "{} {}{align_shift}{key}", self.kind, self.size) |
146 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotData as core::fmt::Display>::fmt Unexecuted instantiation: <cranelift_codegen::ir::stackslot::StackSlotData as core::fmt::Display>::fmt |
147 | | } |
148 | | |
149 | | /// Contents of a dynamic stack slot. |
150 | | #[derive(Clone, Debug, PartialEq, Eq, Hash)] |
151 | | #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] |
152 | | pub struct DynamicStackSlotData { |
153 | | /// The kind of stack slot. |
154 | | pub kind: StackSlotKind, |
155 | | |
156 | | /// The type of this slot. |
157 | | pub dyn_ty: DynamicType, |
158 | | } |
159 | | |
160 | | impl DynamicStackSlotData { |
161 | | /// Create a stack slot with the specified byte size. |
162 | 0 | pub fn new(kind: StackSlotKind, dyn_ty: DynamicType) -> Self { |
163 | 0 | assert!(kind == StackSlotKind::ExplicitDynamicSlot); |
164 | 0 | Self { kind, dyn_ty } |
165 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::stackslot::DynamicStackSlotData>::new Unexecuted instantiation: <cranelift_codegen::ir::stackslot::DynamicStackSlotData>::new |
166 | | |
167 | | /// Get the alignment in bytes of this stack slot given the stack pointer alignment. |
168 | 0 | pub fn alignment(&self, max_align: StackSize) -> StackSize { |
169 | 0 | debug_assert!(max_align.is_power_of_two()); |
170 | 0 | max_align |
171 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::stackslot::DynamicStackSlotData>::alignment Unexecuted instantiation: <cranelift_codegen::ir::stackslot::DynamicStackSlotData>::alignment |
172 | | } |
173 | | |
174 | | impl fmt::Display for DynamicStackSlotData { |
175 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
176 | 0 | write!(f, "{} {}", self.kind, self.dyn_ty) |
177 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::stackslot::DynamicStackSlotData as core::fmt::Display>::fmt Unexecuted instantiation: <cranelift_codegen::ir::stackslot::DynamicStackSlotData as core::fmt::Display>::fmt |
178 | | } |
179 | | |
180 | | /// All allocated stack slots. |
181 | | pub type StackSlots = PrimaryMap<StackSlot, StackSlotData>; |
182 | | |
183 | | /// All allocated dynamic stack slots. |
184 | | pub type DynamicStackSlots = PrimaryMap<DynamicStackSlot, DynamicStackSlotData>; |
185 | | |
186 | | #[cfg(test)] |
187 | | mod tests { |
188 | | use super::*; |
189 | | use crate::ir::Function; |
190 | | use crate::ir::types::*; |
191 | | use crate::ir::{DynamicTypeData, GlobalValueData}; |
192 | | use alloc::string::ToString; |
193 | | |
194 | | #[test] |
195 | | fn stack_slot() { |
196 | | let mut func = Function::new(); |
197 | | |
198 | | let ss0 = |
199 | | func.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4, 0)); |
200 | | let ss1 = |
201 | | func.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 8, 0)); |
202 | | assert_eq!(ss0.to_string(), "ss0"); |
203 | | assert_eq!(ss1.to_string(), "ss1"); |
204 | | |
205 | | assert_eq!(func.sized_stack_slots[ss0].size, 4); |
206 | | assert_eq!(func.sized_stack_slots[ss1].size, 8); |
207 | | |
208 | | assert_eq!(func.sized_stack_slots[ss0].to_string(), "explicit_slot 4"); |
209 | | assert_eq!(func.sized_stack_slots[ss1].to_string(), "explicit_slot 8"); |
210 | | } |
211 | | |
212 | | #[test] |
213 | | fn dynamic_stack_slot() { |
214 | | let mut func = Function::new(); |
215 | | |
216 | | let int_vector_ty = I32X4; |
217 | | let fp_vector_ty = F64X2; |
218 | | let scale0 = GlobalValueData::DynScaleTargetConst { |
219 | | vector_type: int_vector_ty, |
220 | | }; |
221 | | let scale1 = GlobalValueData::DynScaleTargetConst { |
222 | | vector_type: fp_vector_ty, |
223 | | }; |
224 | | let gv0 = func.create_global_value(scale0); |
225 | | let gv1 = func.create_global_value(scale1); |
226 | | let dtd0 = DynamicTypeData::new(int_vector_ty, gv0); |
227 | | let dtd1 = DynamicTypeData::new(fp_vector_ty, gv1); |
228 | | let dt0 = func.dfg.make_dynamic_ty(dtd0); |
229 | | let dt1 = func.dfg.make_dynamic_ty(dtd1); |
230 | | |
231 | | let dss0 = func.create_dynamic_stack_slot(DynamicStackSlotData::new( |
232 | | StackSlotKind::ExplicitDynamicSlot, |
233 | | dt0, |
234 | | )); |
235 | | let dss1 = func.create_dynamic_stack_slot(DynamicStackSlotData::new( |
236 | | StackSlotKind::ExplicitDynamicSlot, |
237 | | dt1, |
238 | | )); |
239 | | assert_eq!(dss0.to_string(), "dss0"); |
240 | | assert_eq!(dss1.to_string(), "dss1"); |
241 | | |
242 | | assert_eq!( |
243 | | func.dynamic_stack_slots[dss0].to_string(), |
244 | | "explicit_dynamic_slot dt0" |
245 | | ); |
246 | | assert_eq!( |
247 | | func.dynamic_stack_slots[dss1].to_string(), |
248 | | "explicit_dynamic_slot dt1" |
249 | | ); |
250 | | } |
251 | | } |