duskphantom_middle/transform/
ldce.rs1use std::{
18 collections::{HashSet, VecDeque},
19 pin::Pin,
20};
21
22use crate::{
23 analysis::{
24 effect_analysis::EffectAnalysis,
25 loop_tools::{LoopForest, LoopPtr},
26 },
27 ir::{
28 instruction::{downcast_ref, misc_inst::Call, InstType},
29 BBPtr, InstPtr,
30 },
31 IRBuilder,
32};
33use anyhow::{Ok, Result};
34
35use super::loop_optimization::loop_forest_post_order;
36
37type IRBuilderWraper = Pin<Box<IRBuilder>>;
38
39pub struct LDCE<'a> {
40 _ir_builder: &'a mut IRBuilderWraper,
41 check_set: HashSet<InstPtr>,
42 loop_bbs: HashSet<BBPtr>,
43 effect_analysis: &'a EffectAnalysis,
44}
45
46impl<'a> LDCE<'a> {
47 pub fn new(
48 _ir_builder: &'a mut IRBuilderWraper,
49 effect_analysis: &'a EffectAnalysis,
50 ) -> LDCE<'a> {
51 Self {
52 _ir_builder,
53 check_set: HashSet::new(),
54 loop_bbs: HashSet::new(),
55 effect_analysis,
56 }
57 }
58
59 pub fn run(&mut self, forest: &mut LoopForest) -> Result<()> {
60 loop_forest_post_order(forest, |x| self.ldce_one_loop(x))
61 }
62
63 fn ldce_one_loop(&mut self, lo: LoopPtr) -> Result<()> {
64 self.loop_bbs.clear();
65 {
66 let mut queue = VecDeque::from([lo]);
67 while let Some(lo) = queue.pop_back() {
68 self.loop_bbs.extend(lo.blocks.iter());
69 queue.extend(lo.sub_loops.iter());
70 }
71 }
72
73 lo.blocks.iter().try_for_each(|&x| self.ldce_one_bb(x))
74 }
75
76 fn ldce_one_bb(&mut self, bb: BBPtr) -> Result<()> {
77 let mut cur_set = HashSet::new();
78 for inst in bb.iter() {
79 if self.check_set.contains(&inst) {
80 continue;
81 }
82 cur_set.extend(self.ldce_inst(inst)?);
83 }
84 cur_set.into_iter().for_each(|mut x| x.remove_self());
85 Ok(())
86 }
87
88 fn ldce_inst(&mut self, inst: InstPtr) -> Result<HashSet<InstPtr>> {
89 let check_user_out_loop = |inst: InstPtr| {
90 inst.get_user()
91 .iter()
92 .any(|x| self.loop_bbs.contains(&x.get_parent_bb().unwrap()))
93 };
94 if check_user_out_loop(inst) {
95 self.check_set.insert(inst);
96 return Ok(HashSet::new());
97 }
98
99 let mut cur_set = HashSet::from([inst]);
100 let mut queue = VecDeque::from([inst]);
101 while let Some(inst) = queue.pop_back() {
102 if !self.can_delete_inst(inst) || check_user_out_loop(inst) {
103 self.check_set
104 .extend(cur_set.iter().chain(inst.get_user().iter()));
105 return Ok(HashSet::new());
106 }
107 queue.extend(inst.get_user().iter().filter(|x| !cur_set.contains(x)));
108 cur_set.extend(inst.get_user().iter());
109 }
110
111 self.check_set.extend(cur_set.iter());
112 Ok(cur_set)
113 }
114
115 fn can_delete_inst(&self, inst: InstPtr) -> bool {
116 let call_no_effect = if inst.get_type() == InstType::Call {
117 let call = downcast_ref::<Call>(inst.as_ref().as_ref());
118 !(self.effect_analysis.has_mem_output.contains(&call.func)
119 || self.effect_analysis.has_io_input.contains(&call.func)
120 || self.effect_analysis.has_io_output.contains(&call.func))
121 } else {
122 true
123 };
124 let no_control_or_store = !matches!(
125 inst.get_type(),
126 InstType::Br | InstType::Ret | InstType::Store
127 );
128 call_no_effect && no_control_or_store
129 }
130}