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 From<bool> for PostPassStatus {
147 fn from(ir_was_changed: bool) -> Self {
148 if ir_was_changed {
149 PostPassStatus::Changed
150 } else {
151 PostPassStatus::Unchanged
152 }
153 }
154}
155
156#[allow(unused_variables)]
158pub trait Pass: Sized + Any {
159 type Target: ?Sized + PassTarget;
163
164 #[inline(always)]
166 fn as_any(&self) -> &dyn Any {
167 self as &dyn Any
168 }
169
170 #[inline(always)]
172 fn as_any_mut(&mut self) -> &mut dyn Any {
173 self as &mut dyn Any
174 }
175
176 #[inline(always)]
178 fn into_any(self: Box<Self>) -> Box<dyn Any> {
179 self as Box<dyn Any>
180 }
181
182 fn name(&self) -> &'static str;
184 fn argument(&self) -> &'static str {
186 ""
188 }
189 fn description(&self) -> &'static str {
191 ""
192 }
193 fn info(&self) -> PassInfo {
195 PassInfo::lookup(self.argument()).expect("pass is not currently registered")
196 }
197 fn target_name(&self, context: &Context) -> Option<OperationName> {
199 <<Self as Pass>::Target as PassTarget>::target_name(context)
200 }
201 fn initialize_options(&mut self, options: &str) -> Result<(), Report> {
206 Ok(())
207 }
208 fn print_as_textual_pipeline(&self, f: &mut fmt::Formatter) -> fmt::Result {
212 let argument = self.argument();
213 if !argument.is_empty() {
214 write!(f, "{argument}")
215 } else {
216 write!(f, "unknown<{}>", self.name())
217 }
218 }
219 fn has_statistics(&self) -> bool {
221 !self.statistics().is_empty()
222 }
223 fn statistics(&self) -> &[Box<dyn Statistic>] {
225 &[]
226 }
227 fn statistics_mut(&mut self) -> &mut [Box<dyn Statistic>] {
229 &mut []
230 }
231 fn initialize(&mut self, context: Rc<Context>) -> Result<(), Report> {
242 Ok(())
243 }
244 fn can_schedule_on(&self, name: &OperationName) -> bool;
246 fn run_on_operation(
248 &mut self,
249 op: EntityMut<'_, Self::Target>,
250 state: &mut PassExecutionState,
251 ) -> Result<(), Report>;
252 fn run_pipeline(
257 &mut self,
258 pipeline: &mut OpPassManager,
259 op: OperationRef,
260 state: &mut PassExecutionState,
261 ) -> Result<(), Report> {
262 state.run_pipeline(pipeline, op)
263 }
264}
265
266impl<P> Pass for Box<P>
267where
268 P: Pass,
269{
270 type Target = <P as Pass>::Target;
271
272 fn as_any(&self) -> &dyn Any {
273 (**self).as_any()
274 }
275
276 fn as_any_mut(&mut self) -> &mut dyn Any {
277 (**self).as_any_mut()
278 }
279
280 fn into_any(self: Box<Self>) -> Box<dyn Any> {
281 let pass = Box::into_inner(self);
282 <P as Pass>::into_any(pass)
283 }
284
285 #[inline]
286 fn name(&self) -> &'static str {
287 (**self).name()
288 }
289
290 #[inline]
291 fn argument(&self) -> &'static str {
292 (**self).argument()
293 }
294
295 #[inline]
296 fn description(&self) -> &'static str {
297 (**self).description()
298 }
299
300 #[inline]
301 fn info(&self) -> PassInfo {
302 (**self).info()
303 }
304
305 #[inline]
306 fn target_name(&self, context: &Context) -> Option<OperationName> {
307 (**self).target_name(context)
308 }
309
310 #[inline]
311 fn initialize_options(&mut self, options: &str) -> Result<(), Report> {
312 (**self).initialize_options(options)
313 }
314
315 #[inline]
316 fn print_as_textual_pipeline(&self, f: &mut fmt::Formatter) -> fmt::Result {
317 (**self).print_as_textual_pipeline(f)
318 }
319
320 #[inline]
321 fn has_statistics(&self) -> bool {
322 (**self).has_statistics()
323 }
324
325 #[inline]
326 fn statistics(&self) -> &[Box<dyn Statistic>] {
327 (**self).statistics()
328 }
329
330 #[inline]
331 fn statistics_mut(&mut self) -> &mut [Box<dyn Statistic>] {
332 (**self).statistics_mut()
333 }
334
335 #[inline]
336 fn initialize(&mut self, context: Rc<Context>) -> Result<(), Report> {
337 (**self).initialize(context)
338 }
339
340 #[inline]
341 fn can_schedule_on(&self, name: &OperationName) -> bool {
342 (**self).can_schedule_on(name)
343 }
344
345 #[inline]
346 fn run_on_operation(
347 &mut self,
348 op: EntityMut<'_, Self::Target>,
349 state: &mut PassExecutionState,
350 ) -> Result<(), Report> {
351 (**self).run_on_operation(op, state)
352 }
353
354 #[inline]
355 fn run_pipeline(
356 &mut self,
357 pipeline: &mut OpPassManager,
358 op: OperationRef,
359 state: &mut PassExecutionState,
360 ) -> Result<(), Report> {
361 (**self).run_pipeline(pipeline, op, state)
362 }
363}
364
365pub type DynamicPipelineExecutor =
366 dyn FnMut(&mut OpPassManager, OperationRef) -> Result<(), Report>;
367
368pub struct PassExecutionState {
371 op: OperationRef,
373 context: Rc<Context>,
374 analysis_manager: AnalysisManager,
375 preserved_analyses: PreservedAnalyses,
377 #[allow(unused)]
380 pipeline_executor: Option<Box<DynamicPipelineExecutor>>,
381 post_pass_status: PostPassStatus,
382}
383impl PassExecutionState {
384 pub fn new(
385 op: OperationRef,
386 context: Rc<Context>,
387 analysis_manager: AnalysisManager,
388 pipeline_executor: Option<Box<DynamicPipelineExecutor>>,
389 ) -> Self {
390 Self {
391 op,
392 context,
393 analysis_manager,
394 preserved_analyses: Default::default(),
395 pipeline_executor,
396 post_pass_status: PostPassStatus::Unchanged,
397 }
398 }
399
400 #[inline(always)]
401 pub fn context(&self) -> Rc<Context> {
402 self.context.clone()
403 }
404
405 #[inline(always)]
406 pub const fn current_operation(&self) -> &OperationRef {
407 &self.op
408 }
409
410 #[inline(always)]
411 pub const fn analysis_manager(&self) -> &AnalysisManager {
412 &self.analysis_manager
413 }
414
415 #[inline(always)]
416 pub const fn preserved_analyses(&self) -> &PreservedAnalyses {
417 &self.preserved_analyses
418 }
419
420 #[inline(always)]
421 pub fn preserved_analyses_mut(&mut self) -> &mut PreservedAnalyses {
422 &mut self.preserved_analyses
423 }
424
425 #[inline(always)]
426 pub fn post_pass_status(&self) -> &PostPassStatus {
427 &self.post_pass_status
428 }
429
430 #[inline(always)]
431 pub fn set_post_pass_status(&mut self, post_pass_status: PostPassStatus) {
432 self.post_pass_status = post_pass_status;
433 }
434
435 pub fn run_pipeline(
436 &mut self,
437 pipeline: &mut OpPassManager,
438 op: OperationRef,
439 ) -> Result<(), Report> {
440 if let Some(pipeline_executor) = self.pipeline_executor.as_deref_mut() {
441 pipeline_executor(pipeline, op)
442 } else {
443 Ok(())
444 }
445 }
446}