cranelift_codegen/ir/
stackslot.rs1use crate::entity::PrimaryMap;
7use crate::ir::entities::{DynamicStackSlot, DynamicType};
8use crate::ir::StackSlot;
9use core::fmt;
10use core::str::FromStr;
11
12#[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::{Deserialize, Serialize};
21
22pub type StackSize = u32;
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
31#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
32pub enum StackSlotKind {
33 ExplicitSlot,
36 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#[derive(Clone, Debug, PartialEq, Eq, Hash)]
66#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
67pub struct StackSlotData {
68 pub kind: StackSlotKind,
70
71 pub size: StackSize,
73}
74
75impl StackSlotData {
76 pub fn new(kind: StackSlotKind, size: StackSize) -> Self {
78 Self { kind, size }
79 }
80
81 pub fn alignment(&self, max_align: StackSize) -> StackSize {
83 debug_assert!(max_align.is_power_of_two());
84 if self.kind == StackSlotKind::ExplicitDynamicSlot {
85 max_align
86 } else {
87 let x = self.size | max_align;
90 x & x.wrapping_neg()
92 }
93 }
94}
95
96impl fmt::Display for StackSlotData {
97 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 write!(f, "{} {}", self.kind, self.size)
99 }
100}
101
102#[derive(Clone, Debug, PartialEq, Eq, Hash)]
104#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
105pub struct DynamicStackSlotData {
106 pub kind: StackSlotKind,
108
109 pub dyn_ty: DynamicType,
111}
112
113impl DynamicStackSlotData {
114 pub fn new(kind: StackSlotKind, dyn_ty: DynamicType) -> Self {
116 assert!(kind == StackSlotKind::ExplicitDynamicSlot);
117 Self { kind, dyn_ty }
118 }
119
120 pub fn alignment(&self, max_align: StackSize) -> StackSize {
122 debug_assert!(max_align.is_power_of_two());
123 max_align
124 }
125}
126
127impl fmt::Display for DynamicStackSlotData {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 write!(f, "{} {}", self.kind, self.dyn_ty)
130 }
131}
132
133pub type StackSlots = PrimaryMap<StackSlot, StackSlotData>;
135
136pub type DynamicStackSlots = PrimaryMap<DynamicStackSlot, DynamicStackSlotData>;
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142 use crate::ir::Function;
143 use alloc::string::ToString;
144
145 #[test]
146 fn stack_slot() {
147 let mut func = Function::new();
148
149 let ss0 = func.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 4));
150 let ss1 = func.create_sized_stack_slot(StackSlotData::new(StackSlotKind::ExplicitSlot, 8));
151 assert_eq!(ss0.to_string(), "ss0");
152 assert_eq!(ss1.to_string(), "ss1");
153
154 assert_eq!(func.sized_stack_slots[ss0].size, 4);
155 assert_eq!(func.sized_stack_slots[ss1].size, 8);
156
157 assert_eq!(func.sized_stack_slots[ss0].to_string(), "explicit_slot 4");
158 assert_eq!(func.sized_stack_slots[ss1].to_string(), "explicit_slot 8");
159 }
160
161 #[test]
162 fn dynamic_stack_slot() {
163 let mut func = Function::new();
164
165 let int_vector_ty = I32X4;
166 let fp_vector_ty = F64X2;
167 let scale0 = GlobalValueData::DynScaleTargetConst {
168 vector_type: int_vector_ty,
169 };
170 let scale1 = GlobalValueData::DynScaleTargetConst {
171 vector_type: fp_vector_ty,
172 };
173 let gv0 = func.create_global_value(scale0);
174 let gv1 = func.create_global_value(scale1);
175 let dtd0 = DynamicTypeData::new(int_vector_ty, gv0);
176 let dtd1 = DynamicTypeData::new(fp_vector_ty, gv1);
177 let dt0 = func.dfg.make_dynamic_ty(dtd0);
178 let dt1 = func.dfg.make_dynamic_ty(dtd1);
179
180 let dss0 = func.create_dynamic_stack_slot(DynamicStackSlotData::new(
181 StackSlotKind::ExplicitDynamicSlot,
182 dt0,
183 ));
184 let dss1 = func.create_dynamic_stack_slot(DynamicStackSlotData::new(
185 StackSlotKind::ExplicitDynamicSlot,
186 dt1,
187 ));
188 assert_eq!(dss0.to_string(), "dss0");
189 assert_eq!(dss1.to_string(), "dss1");
190
191 assert_eq!(
192 func.dynamic_stack_slots[dss0].to_string(),
193 "explicit_dynamic_slot dt0"
194 );
195 assert_eq!(
196 func.dynamic_stack_slots[dss1].to_string(),
197 "explicit_dynamic_slot dt1"
198 );
199 }
200
201 #[test]
202 fn alignment() {
203 let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 8);
204
205 assert_eq!(slot.alignment(4), 4);
206 assert_eq!(slot.alignment(8), 8);
207 assert_eq!(slot.alignment(16), 8);
208
209 let slot2 = StackSlotData::new(StackSlotKind::ExplicitSlot, 24);
210
211 assert_eq!(slot2.alignment(4), 4);
212 assert_eq!(slot2.alignment(8), 8);
213 assert_eq!(slot2.alignment(16), 8);
214 assert_eq!(slot2.alignment(32), 8);
215 }
216}