1use crate::alias_analysis::AliasAnalysis;
13use crate::dominator_tree::DominatorTree;
14use crate::egraph::EgraphPass;
15use crate::flowgraph::ControlFlowGraph;
16use crate::inline::{Inline, do_inlining};
17use crate::ir::Function;
18use crate::isa::TargetIsa;
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::{VerifierErrors, VerifierResult, verify_context};
28use crate::{CompileError, timing};
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 pub(crate) regalloc_ctx: regalloc2::Ctx,
60}
61
62impl Context {
63 pub fn new() -> Self {
68 Self::for_function(Function::new())
69 }
70
71 pub fn for_function(func: Function) -> Self {
76 Self {
77 func,
78 cfg: ControlFlowGraph::new(),
79 domtree: DominatorTree::new(),
80 loop_analysis: LoopAnalysis::new(),
81 compiled_code: None,
82 want_disasm: false,
83 regalloc_ctx: regalloc2::Ctx::default(),
84 }
85 }
86
87 pub fn clear(&mut self) {
89 self.func.clear();
90 self.cfg.clear();
91 self.domtree.clear();
92 self.loop_analysis.clear();
93 self.compiled_code = None;
94 self.want_disasm = false;
95 }
96
97 pub fn compiled_code(&self) -> Option<&CompiledCode> {
100 self.compiled_code.as_ref()
101 }
102
103 pub fn take_compiled_code(&mut self) -> Option<CompiledCode> {
106 self.compiled_code.take()
107 }
108
109 pub fn set_disasm(&mut self, val: bool) {
112 self.want_disasm = val;
113 }
114
115 #[deprecated = "use Context::compile"]
117 pub fn compile_and_emit(
118 &mut self,
119 isa: &dyn TargetIsa,
120 mem: &mut Vec<u8>,
121 ctrl_plane: &mut ControlPlane,
122 ) -> CompileResult<'_, &CompiledCode> {
123 let compiled_code = self.compile(isa, ctrl_plane)?;
124 mem.extend_from_slice(compiled_code.code_buffer());
125 Ok(compiled_code)
126 }
127
128 pub fn compile_stencil(
132 &mut self,
133 isa: &dyn TargetIsa,
134 ctrl_plane: &mut ControlPlane,
135 ) -> CodegenResult<CompiledCodeStencil> {
136 let result;
137 trace!("****** START compiling {}", self.func.display_spec());
138 {
139 let _tt = timing::compile();
140
141 self.verify_if(isa)?;
142 self.optimize(isa, ctrl_plane)?;
143 result = isa.compile_function(
144 &self.func,
145 &self.domtree,
146 &self.loop_analysis,
147 &mut self.regalloc_ctx,
148 self.want_disasm,
149 ctrl_plane,
150 );
151 }
152 trace!("****** DONE compiling {}\n", self.func.display_spec());
153 result
154 }
155
156 pub fn optimize(
162 &mut self,
163 isa: &dyn TargetIsa,
164 ctrl_plane: &mut ControlPlane,
165 ) -> CodegenResult<()> {
166 log::debug!(
167 "Number of CLIF instructions to optimize: {}",
168 self.func.dfg.num_insts()
169 );
170 log::debug!(
171 "Number of CLIF blocks to optimize: {}",
172 self.func.dfg.num_blocks()
173 );
174
175 let opt_level = isa.flags().opt_level();
176 crate::trace!(
177 "Optimizing (opt level {:?}):\n{}",
178 opt_level,
179 self.func.display()
180 );
181
182 if isa.flags().enable_nan_canonicalization() {
183 self.canonicalize_nans(isa)?;
184 }
185
186 self.verify_if(isa)?;
187
188 self.compute_cfg();
189 self.compute_domtree();
190 self.eliminate_unreachable_code(isa)?;
191 self.remove_constant_phis(isa)?;
192
193 self.func.dfg.resolve_all_aliases();
194
195 if opt_level != OptLevel::None {
196 self.egraph_pass(isa, ctrl_plane)?;
197 }
198
199 Ok(())
200 }
201
202 pub fn inline(&mut self, inliner: impl Inline) -> CodegenResult<bool> {
206 do_inlining(&mut self.func, inliner)
207 }
208
209 pub fn compile(
222 &mut self,
223 isa: &dyn TargetIsa,
224 ctrl_plane: &mut ControlPlane,
225 ) -> CompileResult<'_, &CompiledCode> {
226 let stencil = self
227 .compile_stencil(isa, ctrl_plane)
228 .map_err(|error| CompileError {
229 inner: error,
230 func: &self.func,
231 })?;
232 Ok(self
233 .compiled_code
234 .insert(stencil.apply_params(&self.func.params)))
235 }
236
237 #[deprecated = "use CompiledCode::get_code_bb_layout"]
241 pub fn get_code_bb_layout(&self) -> Option<(Vec<usize>, Vec<(usize, usize)>)> {
242 self.compiled_code().map(CompiledCode::get_code_bb_layout)
243 }
244
245 #[cfg(feature = "unwind")]
249 #[deprecated = "use CompiledCode::create_unwind_info"]
250 pub fn create_unwind_info(
251 &self,
252 isa: &dyn TargetIsa,
253 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
254 self.compiled_code().unwrap().create_unwind_info(isa)
255 }
256
257 pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> {
263 let mut errors = VerifierErrors::default();
264 let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors);
265
266 if errors.is_empty() {
267 Ok(())
268 } else {
269 Err(errors)
270 }
271 }
272
273 pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> {
275 let fisa = fisa.into();
276 if fisa.flags.enable_verifier() {
277 self.verify(fisa)?;
278 }
279 Ok(())
280 }
281
282 pub fn remove_constant_phis<'a, FOI: Into<FlagsOrIsa<'a>>>(
284 &mut self,
285 fisa: FOI,
286 ) -> CodegenResult<()> {
287 do_remove_constant_phis(&mut self.func, &mut self.domtree);
288 self.verify_if(fisa)?;
289 Ok(())
290 }
291
292 pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
294 let has_vector_support = match isa.triple().architecture {
296 Architecture::Riscv64(_) => match isa.isa_flags().iter().find(|f| f.name == "has_v") {
297 Some(value) => value.as_bool().unwrap_or(false),
298 None => false,
299 },
300 _ => true,
301 };
302 do_nan_canonicalization(&mut self.func, has_vector_support);
303 self.verify_if(isa)
304 }
305
306 pub fn compute_cfg(&mut self) {
308 self.cfg.compute(&self.func)
309 }
310
311 pub fn compute_domtree(&mut self) {
313 self.domtree.compute(&self.func, &self.cfg);
314 }
315
316 pub fn compute_loop_analysis(&mut self) {
318 self.loop_analysis
319 .compute(&self.func, &self.cfg, &self.domtree)
320 }
321
322 pub fn flowgraph(&mut self) {
324 self.compute_cfg();
325 self.compute_domtree()
326 }
327
328 pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()>
330 where
331 FOI: Into<FlagsOrIsa<'a>>,
332 {
333 let domtree = &self.domtree;
334 eliminate_unreachable_code(&mut self.func, &mut self.cfg, |block| {
335 domtree.is_reachable(block)
336 });
337 self.verify_if(fisa)
338 }
339
340 pub fn replace_redundant_loads(&mut self) -> CodegenResult<()> {
346 let mut analysis = AliasAnalysis::new(&self.func, &self.domtree);
347 analysis.compute_and_update_aliases(&mut self.func, &self.cfg);
348 Ok(())
349 }
350
351 #[cfg(feature = "souper-harvest")]
353 pub fn souper_harvest(
354 &mut self,
355 out: &mut std::sync::mpsc::Sender<String>,
356 ) -> CodegenResult<()> {
357 do_souper_harvest(&self.func, out);
358 Ok(())
359 }
360
361 pub fn egraph_pass<'a, FOI>(
363 &mut self,
364 fisa: FOI,
365 ctrl_plane: &mut ControlPlane,
366 ) -> CodegenResult<()>
367 where
368 FOI: Into<FlagsOrIsa<'a>>,
369 {
370 let _tt = timing::egraph();
371
372 trace!(
373 "About to optimize with egraph phase:\n{}",
374 self.func.display()
375 );
376 let fisa = fisa.into();
377 self.compute_loop_analysis();
378 let mut alias_analysis = AliasAnalysis::new(&self.func, &self.domtree);
379 let mut pass = EgraphPass::new(
380 &mut self.func,
381 &self.domtree,
382 &self.loop_analysis,
383 &mut alias_analysis,
384 ctrl_plane,
385 &mut self.cfg,
386 );
387 pass.run();
388 log::debug!("egraph stats: {:?}", pass.stats);
389 trace!("After egraph optimization:\n{}", self.func.display());
390
391 self.compute_cfg();
393 self.compute_domtree();
394 self.compute_loop_analysis();
395
396 self.verify_if(fisa)?;
397
398 Ok(())
399 }
400}