pliron/irbuild/
match_rewrite.rs1use alloc::collections::VecDeque;
8
9use crate::{
10 context::{Context, Ptr},
11 graph::walkers::{IRNode, WalkConfig, uninterruptible::immutable::walk_op},
12 irbuild::{
13 IRStatus,
14 inserter::{Inserter, OpInsertionPoint},
15 listener::{Recorder, RecorderEvent},
16 rewriter::{IRRewriter, Rewriter},
17 },
18 operation::Operation,
19 pass::{AnalysisManager, Pass, PassResult},
20 result::Result,
21 utils::table::HSet,
22};
23
24pub type MatchRewriter = IRRewriter<Recorder>;
26
27pub trait MatchRewrite {
29 fn r#match(&mut self, ctx: &Context, op: Ptr<Operation>) -> bool;
31 fn rewrite(
34 &mut self,
35 ctx: &mut Context,
36 rewriter: &mut MatchRewriter,
37 op: Ptr<Operation>,
38 ) -> Result<()>;
39}
40
41#[derive(Clone, Copy, Debug, Default)]
43pub enum EnqueueOrder {
44 EnqueFront,
45 #[default]
46 EnqueBack,
47}
48
49#[derive(Clone, Debug, Default)]
51pub struct RewriterOrder {
52 pub collect: WalkConfig,
54 pub enque: EnqueueOrder,
56}
57
58pub fn apply_match_rewrite<M: MatchRewrite>(
61 ctx: &mut Context,
62 match_rewrite: &mut M,
63 order: RewriterOrder,
64 op: Ptr<Operation>,
65) -> Result<IRStatus> {
66 let mut to_rewrite = VecDeque::new();
67
68 struct WalkerState<'a, M> {
70 match_rewrite: &'a mut M,
71 to_rewrite: &'a mut VecDeque<Ptr<Operation>>,
72 }
73 let mut state = WalkerState {
74 match_rewrite,
75 to_rewrite: &mut to_rewrite,
76 };
77 fn walker_callback<M: MatchRewrite>(ctx: &Context, state: &mut WalkerState<M>, node: IRNode) {
79 if let IRNode::Operation(op) = node
80 && state.match_rewrite.r#match(ctx, op)
81 {
82 state.to_rewrite.push_back(op);
83 }
84 }
85 walk_op(ctx, &mut state, &order.collect, op, walker_callback);
87
88 let mut erased = HSet::<Ptr<Operation>>::default();
89 let mut rewriter = MatchRewriter::default();
90 rewriter.set_listener(Recorder::default());
91
92 while !to_rewrite.is_empty() {
94 let op = to_rewrite.pop_front().unwrap();
95 if erased.contains(&op) {
96 continue;
97 }
98 rewriter.set_insertion_point(OpInsertionPoint::BeforeOperation(op));
99 match_rewrite.rewrite(ctx, &mut rewriter, op)?;
100 let listener = rewriter.get_listener_mut();
101 for event in &listener.events {
103 if let RecorderEvent::ErasedOperation(erased_op) = event {
104 erased.insert(*erased_op);
105 }
106 }
107 for event in &listener.events {
109 match event {
110 RecorderEvent::ErasedOperation(_) => {
111 }
113 RecorderEvent::InsertedOperation(new_op) => {
114 if !erased.contains(new_op) && match_rewrite.r#match(ctx, *new_op) {
116 match order.enque {
117 EnqueueOrder::EnqueFront => to_rewrite.push_front(*new_op),
118 EnqueueOrder::EnqueBack => to_rewrite.push_back(*new_op),
119 }
120 }
121 }
122 RecorderEvent::ReplacedValueUses { .. } => {
123 }
125 RecorderEvent::InsertedBlock(_) => {
126 }
128 RecorderEvent::ErasedBlock(_) => {
129 }
133 RecorderEvent::ErasedRegion(_) => {
134 }
138 RecorderEvent::ValueTypeChanged { .. } => {
139 }
141 RecorderEvent::UnlinkedOperation(_op, _prev_position) => {
142 }
144 RecorderEvent::UnlinkedBlock(_block, _prev_position) => {
145 }
147 }
148 }
149 listener.clear();
150 }
151 Ok(rewriter.is_modified().into())
152}
153
154pub struct PassWrapper<M: MatchRewrite> {
156 name: &'static str,
157 match_rewrite: M,
158 rewrite_order: RewriterOrder,
159}
160
161impl<M: MatchRewrite> PassWrapper<M> {
162 pub fn new(name: &'static str, match_rewrite: M) -> Self {
164 Self {
165 name,
166 match_rewrite,
167 rewrite_order: RewriterOrder::default(),
168 }
169 }
170
171 pub fn set_rewrite_order(mut self, order: RewriterOrder) -> Self {
173 self.rewrite_order = order;
174 self
175 }
176}
177
178impl<M: MatchRewrite> Pass for PassWrapper<M> {
179 fn run(
180 &mut self,
181 op: Ptr<Operation>,
182 ctx: &mut Context,
183 _analyses: &mut AnalysisManager,
184 ) -> Result<PassResult> {
185 let mut pass_result = PassResult::default();
186 pass_result.ir_changed |=
187 apply_match_rewrite(ctx, &mut self.match_rewrite, self.rewrite_order.clone(), op)?;
188 Ok(pass_result)
189 }
190
191 fn name(&self) -> &str {
192 self.name
193 }
194}