1use alloc::{boxed::Box, rc::Rc};
2use core::{any::Any, fmt};
3
4use super::*;
5use crate::{Context, EntityMut, OperationName, OperationRef, Report};
6
7#[allow(unused_variables)]
13pub trait OperationPass {
14 fn as_any(&self) -> &dyn Any;
15 fn as_any_mut(&mut self) -> &mut dyn Any;
16 fn into_any(self: Box<Self>) -> Box<dyn Any>;
17 fn name(&self) -> &'static str;
18
19 fn argument(&self) -> &'static str {
20 ""
22 }
23 fn description(&self) -> &'static str {
24 ""
25 }
26 fn info(&self) -> PassInfo {
27 PassInfo::lookup(self.argument()).expect("could not find pass information")
28 }
29 fn target_name(&self, context: &Context) -> Option<OperationName>;
31 fn initialize_options(&mut self, options: &str) -> Result<(), Report> {
32 Ok(())
33 }
34 fn print_as_textual_pipeline(&self, f: &mut fmt::Formatter) -> fmt::Result;
35 fn has_statistics(&self) -> bool {
36 !self.statistics().is_empty()
37 }
38 fn statistics(&self) -> &[Box<dyn Statistic>];
39 fn statistics_mut(&mut self) -> &mut [Box<dyn Statistic>];
40 fn initialize(&mut self, context: Rc<Context>) -> Result<(), Report> {
41 Ok(())
42 }
43 fn can_schedule_on(&self, name: &OperationName) -> bool;
44 fn run_on_operation(
45 &mut self,
46 op: OperationRef,
47 state: &mut PassExecutionState,
48 ) -> Result<(), Report>;
49 fn run_pipeline(
50 &mut self,
51 pipeline: &mut OpPassManager,
52 op: OperationRef,
53 state: &mut PassExecutionState,
54 ) -> Result<(), Report>;
55}
56
57impl<P> OperationPass for P
58where
59 P: Pass + 'static,
60{
61 fn as_any(&self) -> &dyn Any {
62 <P as Pass>::as_any(self)
63 }
64
65 fn as_any_mut(&mut self) -> &mut dyn Any {
66 <P as Pass>::as_any_mut(self)
67 }
68
69 fn into_any(self: Box<Self>) -> Box<dyn Any> {
70 <P as Pass>::into_any(self)
71 }
72
73 fn name(&self) -> &'static str {
74 <P as Pass>::name(self)
75 }
76
77 fn argument(&self) -> &'static str {
78 <P as Pass>::argument(self)
79 }
80
81 fn description(&self) -> &'static str {
82 <P as Pass>::description(self)
83 }
84
85 fn info(&self) -> PassInfo {
86 <P as Pass>::info(self)
87 }
88
89 fn target_name(&self, context: &Context) -> Option<OperationName> {
90 <P as Pass>::target_name(self, context)
91 }
92
93 fn initialize_options(&mut self, options: &str) -> Result<(), Report> {
94 <P as Pass>::initialize_options(self, options)
95 }
96
97 fn print_as_textual_pipeline(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 <P as Pass>::print_as_textual_pipeline(self, f)
99 }
100
101 fn has_statistics(&self) -> bool {
102 <P as Pass>::has_statistics(self)
103 }
104
105 fn statistics(&self) -> &[Box<dyn Statistic>] {
106 <P as Pass>::statistics(self)
107 }
108
109 fn statistics_mut(&mut self) -> &mut [Box<dyn Statistic>] {
110 <P as Pass>::statistics_mut(self)
111 }
112
113 fn initialize(&mut self, context: Rc<Context>) -> Result<(), Report> {
114 <P as Pass>::initialize(self, context)
115 }
116
117 fn can_schedule_on(&self, name: &OperationName) -> bool {
118 <P as Pass>::can_schedule_on(self, name)
119 }
120
121 fn run_on_operation(
122 &mut self,
123 mut op: OperationRef,
124 state: &mut PassExecutionState,
125 ) -> Result<(), Report> {
126 let op = <<P as Pass>::Target as PassTarget>::into_target_mut(&mut op);
127 <P as Pass>::run_on_operation(self, op, state)
128 }
129
130 fn run_pipeline(
131 &mut self,
132 pipeline: &mut OpPassManager,
133 op: OperationRef,
134 state: &mut PassExecutionState,
135 ) -> Result<(), Report> {
136 <P as Pass>::run_pipeline(self, pipeline, op, state)
137 }
138}
139
140#[derive(Debug, PartialEq, Clone, Copy)]
141pub enum PostPassStatus {
142 Unchanged,
143 Changed,
144}
145
146impl PostPassStatus {
147 pub const fn ir_changed(&self) -> bool {
148 matches!(self, Self::Changed)
149 }
150}
151
152impl From<bool> for PostPassStatus {
153 fn from(ir_was_changed: bool) -> Self {
154 if ir_was_changed {
155 PostPassStatus::Changed
156 } else {
157 PostPassStatus::Unchanged
158 }
159 }
160}
161
162impl core::ops::BitOrAssign for PostPassStatus {
163 fn bitor_assign(&mut self, rhs: Self) {
164 if rhs.ir_changed() {
165 *self = PostPassStatus::Changed;
166 }
167 }
168}
169
170#[allow(unused_variables)]
172pub trait Pass: Sized + Any {
173 type Target: ?Sized + PassTarget;
177
178 #[inline(always)]
180 fn as_any(&self) -> &dyn Any {
181 self as &dyn Any
182 }
183
184 #[inline(always)]
186 fn as_any_mut(&mut self) -> &mut dyn Any {
187 self as &mut dyn Any
188 }
189
190 #[inline(always)]
192 fn into_any(self: Box<Self>) -> Box<dyn Any> {
193 self as Box<dyn Any>
194 }
195
196 fn name(&self) -> &'static str;
198 fn argument(&self) -> &'static str {
200 ""
202 }
203 fn description(&self) -> &'static str {
205 ""
206 }
207 fn info(&self) -> PassInfo {
209 PassInfo::lookup(self.argument()).expect("pass is not currently registered")
210 }
211 fn target_name(&self, context: &Context) -> Option<OperationName> {
213 <<Self as Pass>::Target as PassTarget>::target_name(context)
214 }
215 fn initialize_options(&mut self, options: &str) -> Result<(), Report> {
220 Ok(())
221 }
222 fn print_as_textual_pipeline(&self, f: &mut fmt::Formatter) -> fmt::Result {
226 let argument = self.argument();
227 if !argument.is_empty() {
228 write!(f, "{argument}")
229 } else {
230 write!(f, "unknown<{}>", self.name())
231 }
232 }
233 fn has_statistics(&self) -> bool {
235 !self.statistics().is_empty()
236 }
237 fn statistics(&self) -> &[Box<dyn Statistic>] {
239 &[]
240 }
241 fn statistics_mut(&mut self) -> &mut [Box<dyn Statistic>] {
243 &mut []
244 }
245 fn initialize(&mut self, context: Rc<Context>) -> Result<(), Report> {
256 Ok(())
257 }
258 fn can_schedule_on(&self, name: &OperationName) -> bool;
260 fn run_on_operation(
262 &mut self,
263 op: EntityMut<'_, Self::Target>,
264 state: &mut PassExecutionState,
265 ) -> Result<(), Report>;
266 fn run_pipeline(
271 &mut self,
272 pipeline: &mut OpPassManager,
273 op: OperationRef,
274 state: &mut PassExecutionState,
275 ) -> Result<(), Report> {
276 state.run_pipeline(pipeline, op)
277 }
278}
279
280impl<P> Pass for Box<P>
281where
282 P: Pass,
283{
284 type Target = <P as Pass>::Target;
285
286 fn as_any(&self) -> &dyn Any {
287 <P as Pass>::as_any(self)
288 }
289
290 fn as_any_mut(&mut self) -> &mut dyn Any {
291 <P as Pass>::as_any_mut(self)
292 }
293
294 fn into_any(self: Box<Self>) -> Box<dyn Any> {
295 let pass = Box::into_inner(self);
296 <P as Pass>::into_any(pass)
297 }
298
299 #[inline]
300 fn name(&self) -> &'static str {
301 <P as Pass>::name(self)
302 }
303
304 #[inline]
305 fn argument(&self) -> &'static str {
306 (**self).argument()
307 }
308
309 #[inline]
310 fn description(&self) -> &'static str {
311 (**self).description()
312 }
313
314 #[inline]
315 fn info(&self) -> PassInfo {
316 (**self).info()
317 }
318
319 #[inline]
320 fn target_name(&self, context: &Context) -> Option<OperationName> {
321 (**self).target_name(context)
322 }
323
324 #[inline]
325 fn initialize_options(&mut self, options: &str) -> Result<(), Report> {
326 (**self).initialize_options(options)
327 }
328
329 #[inline]
330 fn print_as_textual_pipeline(&self, f: &mut fmt::Formatter) -> fmt::Result {
331 (**self).print_as_textual_pipeline(f)
332 }
333
334 #[inline]
335 fn has_statistics(&self) -> bool {
336 (**self).has_statistics()
337 }
338
339 #[inline]
340 fn statistics(&self) -> &[Box<dyn Statistic>] {
341 (**self).statistics()
342 }
343
344 #[inline]
345 fn statistics_mut(&mut self) -> &mut [Box<dyn Statistic>] {
346 (**self).statistics_mut()
347 }
348
349 #[inline]
350 fn initialize(&mut self, context: Rc<Context>) -> Result<(), Report> {
351 (**self).initialize(context)
352 }
353
354 #[inline]
355 fn can_schedule_on(&self, name: &OperationName) -> bool {
356 (**self).can_schedule_on(name)
357 }
358
359 #[inline]
360 fn run_on_operation(
361 &mut self,
362 op: EntityMut<'_, Self::Target>,
363 state: &mut PassExecutionState,
364 ) -> Result<(), Report> {
365 (**self).run_on_operation(op, state)
366 }
367
368 #[inline]
369 fn run_pipeline(
370 &mut self,
371 pipeline: &mut OpPassManager,
372 op: OperationRef,
373 state: &mut PassExecutionState,
374 ) -> Result<(), Report> {
375 (**self).run_pipeline(pipeline, op, state)
376 }
377}
378
379pub type DynamicPipelineExecutor =
380 dyn FnMut(&mut OpPassManager, OperationRef) -> Result<(), Report>;
381
382pub struct PassExecutionState {
385 op: OperationRef,
387 context: Rc<Context>,
388 analysis_manager: AnalysisManager,
389 preserved_analyses: PreservedAnalyses,
391 #[allow(unused)]
394 pipeline_executor: Option<Box<DynamicPipelineExecutor>>,
395 post_pass_status: PostPassStatus,
396}
397impl PassExecutionState {
398 pub fn new(
399 op: OperationRef,
400 context: Rc<Context>,
401 analysis_manager: AnalysisManager,
402 pipeline_executor: Option<Box<DynamicPipelineExecutor>>,
403 ) -> Self {
404 Self {
405 op,
406 context,
407 analysis_manager,
408 preserved_analyses: Default::default(),
409 pipeline_executor,
410 post_pass_status: PostPassStatus::Unchanged,
411 }
412 }
413
414 #[inline(always)]
415 pub fn context(&self) -> Rc<Context> {
416 self.context.clone()
417 }
418
419 #[inline(always)]
420 pub const fn current_operation(&self) -> &OperationRef {
421 &self.op
422 }
423
424 #[inline(always)]
425 pub const fn analysis_manager(&self) -> &AnalysisManager {
426 &self.analysis_manager
427 }
428
429 #[inline(always)]
430 pub const fn preserved_analyses(&self) -> &PreservedAnalyses {
431 &self.preserved_analyses
432 }
433
434 #[inline(always)]
435 pub fn preserved_analyses_mut(&mut self) -> &mut PreservedAnalyses {
436 &mut self.preserved_analyses
437 }
438
439 #[inline(always)]
440 pub fn post_pass_status(&self) -> &PostPassStatus {
441 &self.post_pass_status
442 }
443
444 #[inline(always)]
445 pub fn set_post_pass_status(&mut self, post_pass_status: PostPassStatus) {
446 self.post_pass_status = post_pass_status;
447 }
448
449 pub fn run_pipeline(
450 &mut self,
451 pipeline: &mut OpPassManager,
452 op: OperationRef,
453 ) -> Result<(), Report> {
454 if let Some(pipeline_executor) = self.pipeline_executor.as_deref_mut() {
455 pipeline_executor(pipeline, op)
456 } else {
457 Ok(())
458 }
459 }
460}