1use crate::alias_analysis::AliasAnalysis;
13use crate::dce::do_dce;
14use crate::dominator_tree::DominatorTree;
15use crate::egraph::EgraphPass;
16use crate::flowgraph::ControlFlowGraph;
17use crate::ir::Function;
18use crate::isa::TargetIsa;
19use crate::legalizer::simple_legalize;
20use crate::licm::do_licm;
21use crate::loop_analysis::LoopAnalysis;
22use crate::machinst::{CompiledCode, CompiledCodeStencil};
23use crate::nan_canonicalization::do_nan_canonicalization;
24use crate::remove_constant_phis::do_remove_constant_phis;
25use crate::result::{CodegenResult, CompileResult};
26use crate::settings::{FlagsOrIsa, OptLevel};
27use crate::simple_gvn::do_simple_gvn;
28use crate::simple_preopt::do_preopt;
29use crate::trace;
30use crate::unreachable_code::eliminate_unreachable_code;
31use crate::verifier::{verify_context, VerifierErrors, VerifierResult};
32use crate::{timing, CompileError};
33#[cfg(feature = "souper-harvest")]
34use alloc::string::String;
35use alloc::vec::Vec;
36
37#[cfg(feature = "souper-harvest")]
38use crate::souper_harvest::do_souper_harvest;
39
40pub struct Context {
42 pub func: Function,
44
45 pub cfg: ControlFlowGraph,
47
48 pub domtree: DominatorTree,
50
51 pub loop_analysis: LoopAnalysis,
53
54 pub(crate) compiled_code: Option<CompiledCode>,
56
57 pub want_disasm: bool,
59}
60
61impl Context {
62 pub fn new() -> Self {
67 Self::for_function(Function::new())
68 }
69
70 pub fn for_function(func: Function) -> Self {
75 Self {
76 func,
77 cfg: ControlFlowGraph::new(),
78 domtree: DominatorTree::new(),
79 loop_analysis: LoopAnalysis::new(),
80 compiled_code: None,
81 want_disasm: false,
82 }
83 }
84
85 pub fn clear(&mut self) {
87 self.func.clear();
88 self.cfg.clear();
89 self.domtree.clear();
90 self.loop_analysis.clear();
91 self.compiled_code = None;
92 self.want_disasm = false;
93 }
94
95 pub fn compiled_code(&self) -> Option<&CompiledCode> {
98 self.compiled_code.as_ref()
99 }
100
101 pub fn set_disasm(&mut self, val: bool) {
104 self.want_disasm = val;
105 }
106
107 pub fn compile_and_emit(
124 &mut self,
125 isa: &dyn TargetIsa,
126 mem: &mut Vec<u8>,
127 ) -> CompileResult<&CompiledCode> {
128 let compiled_code = self.compile(isa)?;
129 mem.extend_from_slice(compiled_code.code_buffer());
130 Ok(compiled_code)
131 }
132
133 pub fn compile_stencil(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CompiledCodeStencil> {
137 let _tt = timing::compile();
138
139 self.verify_if(isa)?;
140
141 self.optimize(isa)?;
142
143 isa.compile_function(&self.func, &self.domtree, self.want_disasm)
144 }
145
146 pub fn optimize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
152 log::debug!(
153 "Number of CLIF instructions to optimize: {}",
154 self.func.dfg.num_insts()
155 );
156 log::debug!(
157 "Number of CLIF blocks to optimize: {}",
158 self.func.dfg.num_blocks()
159 );
160
161 let opt_level = isa.flags().opt_level();
162 crate::trace!(
163 "Optimizing (opt level {:?}):\n{}",
164 opt_level,
165 self.func.display()
166 );
167
168 self.compute_cfg();
169 if !isa.flags().use_egraphs() && opt_level != OptLevel::None {
170 self.preopt(isa)?;
171 }
172 if isa.flags().enable_nan_canonicalization() {
173 self.canonicalize_nans(isa)?;
174 }
175
176 self.legalize(isa)?;
177
178 if !isa.flags().use_egraphs() && opt_level != OptLevel::None {
179 self.compute_domtree();
180 self.compute_loop_analysis();
181 self.licm(isa)?;
182 self.simple_gvn(isa)?;
183 }
184
185 self.compute_domtree();
186 self.eliminate_unreachable_code(isa)?;
187
188 if opt_level != OptLevel::None {
189 self.dce(isa)?;
190 }
191
192 self.remove_constant_phis(isa)?;
193
194 if opt_level != OptLevel::None {
195 if isa.flags().use_egraphs() {
196 self.egraph_pass()?;
197 } else if isa.flags().enable_alias_analysis() {
198 for _ in 0..2 {
199 self.replace_redundant_loads()?;
200 self.simple_gvn(isa)?;
201 }
202 }
203 }
204
205 Ok(())
206 }
207
208 pub fn compile(&mut self, isa: &dyn TargetIsa) -> CompileResult<&CompiledCode> {
216 let stencil = self.compile_stencil(isa).map_err(|error| CompileError {
217 inner: error,
218 func: &self.func,
219 })?;
220 Ok(self
221 .compiled_code
222 .insert(stencil.apply_params(&self.func.params)))
223 }
224
225 #[deprecated = "use CompiledCode::get_code_bb_layout"]
229 pub fn get_code_bb_layout(&self) -> Option<(Vec<usize>, Vec<(usize, usize)>)> {
230 self.compiled_code().map(CompiledCode::get_code_bb_layout)
231 }
232
233 #[cfg(feature = "unwind")]
237 #[deprecated = "use CompiledCode::create_unwind_info"]
238 pub fn create_unwind_info(
239 &self,
240 isa: &dyn TargetIsa,
241 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
242 self.compiled_code().unwrap().create_unwind_info(isa)
243 }
244
245 pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> {
249 let mut errors = VerifierErrors::default();
250 let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors);
251
252 if errors.is_empty() {
253 Ok(())
254 } else {
255 Err(errors)
256 }
257 }
258
259 pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> {
261 let fisa = fisa.into();
262 if fisa.flags.enable_verifier() {
263 self.verify(fisa)?;
264 }
265 Ok(())
266 }
267
268 pub fn dce<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> {
270 do_dce(&mut self.func, &mut self.domtree);
271 self.verify_if(fisa)?;
272 Ok(())
273 }
274
275 pub fn remove_constant_phis<'a, FOI: Into<FlagsOrIsa<'a>>>(
277 &mut self,
278 fisa: FOI,
279 ) -> CodegenResult<()> {
280 do_remove_constant_phis(&mut self.func, &mut self.domtree);
281 self.verify_if(fisa)?;
282 Ok(())
283 }
284
285 pub fn preopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
287 do_preopt(&mut self.func, isa);
288 self.verify_if(isa)?;
289 Ok(())
290 }
291
292 pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
294 do_nan_canonicalization(&mut self.func);
295 self.verify_if(isa)
296 }
297
298 pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
300 self.domtree.clear();
303 self.loop_analysis.clear();
304
305 simple_legalize(&mut self.func, &mut self.cfg, isa);
307 self.verify_if(isa)
308 }
309
310 pub fn compute_cfg(&mut self) {
312 self.cfg.compute(&self.func)
313 }
314
315 pub fn compute_domtree(&mut self) {
317 self.domtree.compute(&self.func, &self.cfg)
318 }
319
320 pub fn compute_loop_analysis(&mut self) {
322 self.loop_analysis
323 .compute(&self.func, &self.cfg, &self.domtree)
324 }
325
326 pub fn flowgraph(&mut self) {
328 self.compute_cfg();
329 self.compute_domtree()
330 }
331
332 pub fn simple_gvn<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> {
334 do_simple_gvn(&mut self.func, &mut self.domtree);
335 self.verify_if(fisa)
336 }
337
338 pub fn licm(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
340 do_licm(
341 &mut self.func,
342 &mut self.cfg,
343 &mut self.domtree,
344 &mut self.loop_analysis,
345 );
346 self.verify_if(isa)
347 }
348
349 pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()>
351 where
352 FOI: Into<FlagsOrIsa<'a>>,
353 {
354 eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree);
355 self.verify_if(fisa)
356 }
357
358 pub fn replace_redundant_loads(&mut self) -> CodegenResult<()> {
364 let mut analysis = AliasAnalysis::new(&self.func, &self.domtree);
365 analysis.compute_and_update_aliases(&mut self.func);
366 Ok(())
367 }
368
369 #[cfg(feature = "souper-harvest")]
371 pub fn souper_harvest(
372 &mut self,
373 out: &mut std::sync::mpsc::Sender<String>,
374 ) -> CodegenResult<()> {
375 do_souper_harvest(&self.func, out);
376 Ok(())
377 }
378
379 pub fn egraph_pass(&mut self) -> CodegenResult<()> {
381 let _tt = timing::egraph();
382
383 trace!(
384 "About to optimize with egraph phase:\n{}",
385 self.func.display()
386 );
387 self.compute_loop_analysis();
388 let mut alias_analysis = AliasAnalysis::new(&self.func, &self.domtree);
389 let mut pass = EgraphPass::new(
390 &mut self.func,
391 &self.domtree,
392 &self.loop_analysis,
393 &mut alias_analysis,
394 );
395 pass.run();
396 log::debug!("egraph stats: {:?}", pass.stats);
397 trace!("After egraph optimization:\n{}", self.func.display());
398 Ok(())
399 }
400}