1use crate::alias_analysis::AliasAnalysis;
13use crate::dominator_tree::DominatorTree;
14use crate::egraph::EgraphPass;
15use crate::flowgraph::ControlFlowGraph;
16use crate::ir::Function;
17use crate::isa::TargetIsa;
18use crate::legalizer::simple_legalize;
19use crate::loop_analysis::LoopAnalysis;
20use crate::machinst::{CompiledCode, CompiledCodeStencil};
21use crate::nan_canonicalization::do_nan_canonicalization;
22use crate::remove_constant_phis::do_remove_constant_phis;
23use crate::result::{CodegenResult, CompileResult};
24use crate::settings::{FlagsOrIsa, OptLevel};
25use crate::trace;
26use crate::unreachable_code::eliminate_unreachable_code;
27use crate::verifier::{verify_context, VerifierErrors, VerifierResult};
28use crate::{timing, CompileError};
29#[cfg(feature = "souper-harvest")]
30use alloc::string::String;
31use alloc::vec::Vec;
32use cranelift_control::ControlPlane;
33use target_lexicon::Architecture;
34
35#[cfg(feature = "souper-harvest")]
36use crate::souper_harvest::do_souper_harvest;
37
38pub struct Context {
40 pub func: Function,
42
43 pub cfg: ControlFlowGraph,
45
46 pub domtree: DominatorTree,
48
49 pub loop_analysis: LoopAnalysis,
51
52 pub(crate) compiled_code: Option<CompiledCode>,
54
55 pub want_disasm: bool,
57}
58
59impl Context {
60 pub fn new() -> Self {
65 Self::for_function(Function::new())
66 }
67
68 pub fn for_function(func: Function) -> Self {
73 Self {
74 func,
75 cfg: ControlFlowGraph::new(),
76 domtree: DominatorTree::new(),
77 loop_analysis: LoopAnalysis::new(),
78 compiled_code: None,
79 want_disasm: false,
80 }
81 }
82
83 pub fn clear(&mut self) {
85 self.func.clear();
86 self.cfg.clear();
87 self.domtree.clear();
88 self.loop_analysis.clear();
89 self.compiled_code = None;
90 self.want_disasm = false;
91 }
92
93 pub fn compiled_code(&self) -> Option<&CompiledCode> {
96 self.compiled_code.as_ref()
97 }
98
99 pub fn take_compiled_code(&mut self) -> Option<CompiledCode> {
102 self.compiled_code.take()
103 }
104
105 pub fn set_disasm(&mut self, val: bool) {
108 self.want_disasm = val;
109 }
110
111 pub fn compile_and_emit(
128 &mut self,
129 isa: &dyn TargetIsa,
130 mem: &mut Vec<u8>,
131 ctrl_plane: &mut ControlPlane,
132 ) -> CompileResult<&CompiledCode> {
133 let compiled_code = self.compile(isa, ctrl_plane)?;
134 mem.extend_from_slice(compiled_code.code_buffer());
135 Ok(compiled_code)
136 }
137
138 pub fn compile_stencil(
142 &mut self,
143 isa: &dyn TargetIsa,
144 ctrl_plane: &mut ControlPlane,
145 ) -> CodegenResult<CompiledCodeStencil> {
146 let _tt = timing::compile();
147
148 self.verify_if(isa)?;
149
150 self.optimize(isa, ctrl_plane)?;
151
152 isa.compile_function(&self.func, &self.domtree, self.want_disasm, ctrl_plane)
153 }
154
155 pub fn optimize(
161 &mut self,
162 isa: &dyn TargetIsa,
163 ctrl_plane: &mut ControlPlane,
164 ) -> CodegenResult<()> {
165 log::debug!(
166 "Number of CLIF instructions to optimize: {}",
167 self.func.dfg.num_insts()
168 );
169 log::debug!(
170 "Number of CLIF blocks to optimize: {}",
171 self.func.dfg.num_blocks()
172 );
173
174 let opt_level = isa.flags().opt_level();
175 crate::trace!(
176 "Optimizing (opt level {:?}):\n{}",
177 opt_level,
178 self.func.display()
179 );
180
181 self.compute_cfg();
182 if isa.flags().enable_nan_canonicalization() {
183 self.canonicalize_nans(isa)?;
184 }
185
186 self.legalize(isa)?;
187
188 self.compute_domtree();
189 self.eliminate_unreachable_code(isa)?;
190 self.remove_constant_phis(isa)?;
191
192 self.func.dfg.resolve_all_aliases();
193
194 if opt_level != OptLevel::None {
195 self.egraph_pass(isa, ctrl_plane)?;
196 }
197
198 Ok(())
199 }
200
201 pub fn compile(
209 &mut self,
210 isa: &dyn TargetIsa,
211 ctrl_plane: &mut ControlPlane,
212 ) -> CompileResult<&CompiledCode> {
213 let stencil = self
214 .compile_stencil(isa, ctrl_plane)
215 .map_err(|error| CompileError {
216 inner: error,
217 func: &self.func,
218 })?;
219 Ok(self
220 .compiled_code
221 .insert(stencil.apply_params(&self.func.params)))
222 }
223
224 #[deprecated = "use CompiledCode::get_code_bb_layout"]
228 pub fn get_code_bb_layout(&self) -> Option<(Vec<usize>, Vec<(usize, usize)>)> {
229 self.compiled_code().map(CompiledCode::get_code_bb_layout)
230 }
231
232 #[cfg(feature = "unwind")]
236 #[deprecated = "use CompiledCode::create_unwind_info"]
237 pub fn create_unwind_info(
238 &self,
239 isa: &dyn TargetIsa,
240 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
241 self.compiled_code().unwrap().create_unwind_info(isa)
242 }
243
244 pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> {
250 let mut errors = VerifierErrors::default();
251 let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors);
252
253 if errors.is_empty() {
254 Ok(())
255 } else {
256 Err(errors)
257 }
258 }
259
260 pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> {
262 let fisa = fisa.into();
263 if fisa.flags.enable_verifier() {
264 self.verify(fisa)?;
265 }
266 Ok(())
267 }
268
269 pub fn remove_constant_phis<'a, FOI: Into<FlagsOrIsa<'a>>>(
271 &mut self,
272 fisa: FOI,
273 ) -> CodegenResult<()> {
274 do_remove_constant_phis(&mut self.func, &mut self.domtree);
275 self.verify_if(fisa)?;
276 Ok(())
277 }
278
279 pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
281 let has_vector_support = match isa.triple().architecture {
283 Architecture::Riscv64(_) => match isa.isa_flags().iter().find(|f| f.name == "has_v") {
284 Some(value) => value.as_bool().unwrap_or(false),
285 None => false,
286 },
287 _ => true,
288 };
289 do_nan_canonicalization(&mut self.func, has_vector_support);
290 self.verify_if(isa)
291 }
292
293 pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
295 self.domtree.clear();
298 self.loop_analysis.clear();
299
300 simple_legalize(&mut self.func, &mut self.cfg, isa);
302 self.verify_if(isa)
303 }
304
305 pub fn compute_cfg(&mut self) {
307 self.cfg.compute(&self.func)
308 }
309
310 pub fn compute_domtree(&mut self) {
312 self.domtree.compute(&self.func, &self.cfg)
313 }
314
315 pub fn compute_loop_analysis(&mut self) {
317 self.loop_analysis
318 .compute(&self.func, &self.cfg, &self.domtree)
319 }
320
321 pub fn flowgraph(&mut self) {
323 self.compute_cfg();
324 self.compute_domtree()
325 }
326
327 pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()>
329 where
330 FOI: Into<FlagsOrIsa<'a>>,
331 {
332 eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree);
333 self.verify_if(fisa)
334 }
335
336 pub fn replace_redundant_loads(&mut self) -> CodegenResult<()> {
342 let mut analysis = AliasAnalysis::new(&self.func, &self.domtree);
343 analysis.compute_and_update_aliases(&mut self.func);
344 Ok(())
345 }
346
347 #[cfg(feature = "souper-harvest")]
349 pub fn souper_harvest(
350 &mut self,
351 out: &mut std::sync::mpsc::Sender<String>,
352 ) -> CodegenResult<()> {
353 do_souper_harvest(&self.func, out);
354 Ok(())
355 }
356
357 pub fn egraph_pass<'a, FOI>(
359 &mut self,
360 fisa: FOI,
361 ctrl_plane: &mut ControlPlane,
362 ) -> CodegenResult<()>
363 where
364 FOI: Into<FlagsOrIsa<'a>>,
365 {
366 let _tt = timing::egraph();
367
368 trace!(
369 "About to optimize with egraph phase:\n{}",
370 self.func.display()
371 );
372 let fisa = fisa.into();
373 self.compute_loop_analysis();
374 let mut alias_analysis = AliasAnalysis::new(&self.func, &self.domtree);
375 let mut pass = EgraphPass::new(
376 &mut self.func,
377 &self.domtree,
378 &self.loop_analysis,
379 &mut alias_analysis,
380 &fisa.flags,
381 ctrl_plane,
382 );
383 pass.run();
384 log::debug!("egraph stats: {:?}", pass.stats);
385 trace!("pinned_union_count: {}", pass.eclasses.pinned_union_count);
386 trace!("After egraph optimization:\n{}", self.func.display());
387
388 self.verify_if(fisa)
389 }
390}