1use crate::entity::PrimaryMap;
7use crate::ir::StackSlot;
8use crate::ir::entities::{DynamicStackSlot, DynamicType};
9use core::fmt;
10use core::str::FromStr;
11
12#[cfg(feature = "enable-serde")]
13use serde_derive::{Deserialize, Serialize};
14
15pub type StackSize = u32;
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
25pub enum StackSlotKind {
26 ExplicitSlot,
29 ExplicitDynamicSlot,
32}
33
34impl FromStr for StackSlotKind {
35 type Err = ();
36
37 fn from_str(s: &str) -> Result<Self, ()> {
38 use self::StackSlotKind::*;
39 match s {
40 "explicit_slot" => Ok(ExplicitSlot),
41 "explicit_dynamic_slot" => Ok(ExplicitDynamicSlot),
42 _ => Err(()),
43 }
44 }
45}
46
47impl fmt::Display for StackSlotKind {
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 use self::StackSlotKind::*;
50 f.write_str(match *self {
51 ExplicitSlot => "explicit_slot",
52 ExplicitDynamicSlot => "explicit_dynamic_slot",
53 })
54 }
55}
56
57#[derive(Clone, Debug, PartialEq, Eq, Hash)]
59#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
60pub struct StackSlotData {
61 pub kind: StackSlotKind,
63
64 pub size: StackSize,
66
67 pub align_shift: u8,
72
73 pub key: Option<StackSlotKey>,
83}
84
85#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
87#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
88pub struct StackSlotKey(u64);
89impl StackSlotKey {
90 pub fn new(value: u64) -> StackSlotKey {
96 StackSlotKey(value)
97 }
98
99 pub fn bits(&self) -> u64 {
101 self.0
102 }
103}
104
105impl StackSlotData {
106 pub fn new(kind: StackSlotKind, size: StackSize, align_shift: u8) -> Self {
108 Self {
109 kind,
110 size,
111 align_shift,
112 key: None,
113 }
114 }
115
116 pub fn new_with_key(
119 kind: StackSlotKind,
120 size: StackSize,
121 align_shift: u8,
122 key: StackSlotKey,
123 ) -> Self {
124 Self {
125 kind,
126 size,
127 align_shift,
128 key: Some(key),
129 }
130 }
131}
132
133impl fmt::Display for StackSlotData {
134 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135 let align_shift = if self.align_shift != 0 {
136 format!(", align = {}", 1u32 << self.align_shift)
137 } else {
138 "".into()
139 };
140 let key = match self.key {
141 Some(value) => format!(", key = {}", value.bits()),
142 None => "".into(),
143 };
144
145 write!(f, "{} {}{align_shift}{key}", self.kind, self.size)
146 }
147}
148
149#[derive(Clone, Debug, PartialEq, Eq, Hash)]
151#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
152pub struct DynamicStackSlotData {
153 pub kind: StackSlotKind,
155
156 pub dyn_ty: DynamicType,
158}
159
160impl DynamicStackSlotData {
161 pub fn new(kind: StackSlotKind, dyn_ty: DynamicType) -> Self {
163 assert!(kind == StackSlotKind::ExplicitDynamicSlot);
164 Self { kind, dyn_ty }
165 }
166
167 pub fn alignment(&self, max_align: StackSize) -> StackSize {
169 debug_assert!(max_align.is_power_of_two());
170 max_align
171 }
172}
173
174impl fmt::Display for DynamicStackSlotData {
175 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176 write!(f, "{} {}", self.kind, self.dyn_ty)
177 }
178}
179
180pub type StackSlots = PrimaryMap<StackSlot, StackSlotData>;
182
183pub type DynamicStackSlots = PrimaryMap<DynamicStackSlot, DynamicStackSlotData>;
185
186#[cfg(test)]
187mod 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}