1use core::{
2 fmt::{self, Display},
3 hash::Hash,
4};
5
6use derive_more::{Eq, PartialEq};
7use derive_new::new;
8use pliron::{
9 attribute::AttrObj,
10 basic_block::BasicBlock,
11 graph::HasLabel,
12 opts::mem2reg::AllocInfo,
13 printable::{self, Printable},
14 region::Region,
15 utils::table::{HMap, SmallMap, SmallSet},
16 value::DefiningEntity,
17};
18
19use crate::prelude::*;
20
21pub type LogicalResult = core::result::Result<(), ()>;
22
23#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
24pub enum DeletionKind {
25 Keep,
26 Delete,
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32pub enum MemoryDefiningEntity {
33 Op(Ptr<Operation>),
34 Block(Ptr<BasicBlock>),
35 LiveOnEntry,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub struct MemoryValue {
40 val_uid: u64,
41 #[eq(skip)]
42 defining_entity: MemoryDefiningEntity,
43}
44
45impl Hash for MemoryValue {
46 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
47 self.val_uid.hash(state);
48 }
49}
50
51impl Display for MemoryValue {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 if self == &MemoryValue::LIVE_ON_ENTRY {
54 write!(f, "LiveOnEntry")
55 } else {
56 write!(f, "M{}", self.val_uid)
57 }
58 }
59}
60
61impl MemoryValue {
62 pub const LIVE_ON_ENTRY: MemoryValue = MemoryValue {
63 val_uid: 0,
64 defining_entity: MemoryDefiningEntity::LiveOnEntry,
65 };
66
67 pub fn defining_entity(&self) -> Option<DefiningEntity> {
68 match self.defining_entity {
69 MemoryDefiningEntity::Op(op) => Some(DefiningEntity::Op(op)),
70 MemoryDefiningEntity::Block(block) => Some(DefiningEntity::Block(block)),
71 MemoryDefiningEntity::LiveOnEntry => None,
72 }
73 }
74}
75
76#[derive(Default)]
77pub struct MemorySSAContext {
78 last_idx: u64,
79}
80
81impl MemorySSAContext {
82 pub fn new_value_in_block(&mut self, block: Ptr<BasicBlock>) -> MemoryValue {
83 self.last_idx += 1;
84 MemoryValue {
85 val_uid: self.last_idx,
86 defining_entity: MemoryDefiningEntity::Block(block),
87 }
88 }
89
90 pub fn new_value_at_op(&mut self, op: Ptr<Operation>) -> MemoryValue {
91 self.last_idx += 1;
92 MemoryValue {
93 val_uid: self.last_idx,
94 defining_entity: MemoryDefiningEntity::Op(op),
95 }
96 }
97}
98
99#[derive(Clone, Copy, PartialEq, Eq, Hash)]
101pub enum MemoryRegionPredecessor {
102 Parent,
103 Block(Ptr<BasicBlock>),
104}
105
106impl Printable for MemoryRegionPredecessor {
107 fn fmt(&self, ctx: &Context, _: &printable::State, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 match self {
109 MemoryRegionPredecessor::Parent => f.write_str("Parent"),
110 MemoryRegionPredecessor::Block(block) => {
111 write!(f, "{}", block.label(ctx))
112 }
113 }
114 }
115}
116
117pub type RegionMemoryPhiInputs = SmallMap<MemoryRegionPredecessor, MemoryValue, 2>;
118pub enum RegionMemoryValue {
119 Forward(MemoryValue),
120 RegionPhi(RegionMemoryPhiInputs),
121}
122
123#[op_interface]
124pub trait PromotableRegionOpInterface {
125 verify_op_succ!();
126
127 fn is_region_promotable(
131 &self,
132 ctx: &Context,
133 alloc: &AllocInfo,
134 region: Ptr<Region>,
135 has_value_stores: bool,
136 ) -> bool;
137
138 fn setup_promotion(
143 &self,
144 ctx: &mut Context,
145 alloc: &AllocInfo,
146 reaching_def: Value,
147 has_value_stores: bool,
148 regions_to_process: &mut SmallMap<Ptr<Region>, Value, 2>,
149 );
150
151 fn finalize_promotion(
156 &self,
157 ctx: &mut Context,
158 alloc: &AllocInfo,
159 entry_reaching_def: Value,
160 has_value_stores: bool,
161 reaching_at_block_end: &HMap<Ptr<BasicBlock>, Value>,
162 ) -> Value;
163}
164
165#[op_interface]
166pub trait MemorySSARegionOpInterface {
167 verify_op_succ!();
168
169 fn setup_memory_ssa(
173 &self,
174 ctx: &Context,
175 state: &mut MemorySSAContext,
176 reaching_def: MemoryValue,
177 has_memory_defs: bool,
178 regions_to_process: &mut SmallMap<Ptr<Region>, MemoryValue, 2>,
179 );
180
181 #[allow(
187 clippy::too_many_arguments,
188 reason = "packing them into structs would be more complex"
189 )]
190 fn finalize_memory_ssa(
191 &self,
192 ctx: &Context,
193 state: &mut MemorySSAContext,
194 entry_reaching_def: MemoryValue,
195 has_memory_defs: bool,
196 reaching_at_region_entry: &HMap<Ptr<Region>, MemoryValue>,
197 reaching_at_block_end: &HMap<Ptr<BasicBlock>, MemoryValue>,
198 region_phis: &mut SmallMap<Ptr<Region>, RegionMemoryPhiInputs, 2>,
199 ) -> RegionMemoryValue;
200}
201
202#[type_interface]
204pub trait DestructurableTypeInterface {
205 verify_ty_succ!();
206
207 fn subelement_index_map(&self, ctx: &Context) -> Option<HMap<AttrObj, TypeHandle>>;
210
211 fn type_at_index(&self, ctx: &Context, index: &AttrObj) -> TypeHandle;
216}
217
218#[op_interface]
221pub trait DestructurableConstructorOpInterface {
222 verify_op_succ!();
223
224 fn destructurable_values(&self, ctx: &Context) -> Vec<DestructurableValueSlot>;
231
232 fn destructure(
238 &self,
239 ctx: &mut Context,
240 value: &DestructurableValueSlot,
241 used_indices: &SmallSet<AttrObj, 8>,
242 rewriter: &mut PassRewriter,
243 new_constructors: &mut Vec<TraitOp<dyn DestructurableConstructorOpInterface>>,
244 ) -> HMap<AttrObj, ValueSlot>;
245
246 fn handle_destructuring_complete(
253 &self,
254 ctx: &mut Context,
255 value: &DestructurableValueSlot,
256 rewriter: &mut PassRewriter,
257 ) -> Option<TraitOp<dyn DestructurableConstructorOpInterface>>;
258}
259
260#[op_interface]
262pub trait DestructurableAccessorOpInterface {
263 verify_op_succ!();
264
265 fn can_rewire(
276 &self,
277 ctx: &Context,
278 value: &DestructurableValueSlot,
279 used_indices: &mut SmallSet<AttrObj, 8>,
280 must_be_safely_used: &mut Vec<ValueSlot>,
281 ) -> bool;
282
283 fn rewire(
289 &self,
290 ctx: &mut Context,
291 value: &DestructurableValueSlot,
292 subvalues: &HMap<AttrObj, ValueSlot>,
293 rewriter: &mut PassRewriter,
294 ) -> DeletionKind;
295}
296
297#[op_interface]
298pub trait SafeMemorySlotAccessOpInterface {
299 verify_op_succ!();
300
301 #[allow(clippy::result_unit_err)]
302 fn ensure_only_safe_accesses(
313 &self,
314 ctx: &Context,
315 value: &ValueSlot,
316 must_be_safely_used: &mut Vec<ValueSlot>,
317 ) -> LogicalResult;
318}
319
320#[derive(new, Debug)]
321pub struct ValueSlot {
322 pub value: Value,
323 pub elem_ty: TypeHandle,
324}
325
326#[derive(Debug)]
327pub struct DestructurableValueSlot {
328 pub slot: ValueSlot,
329 pub subelement_types: HMap<AttrObj, TypeHandle>,
330}