1use crate::alias_analysis::AliasAnalysis;
13use crate::dominator_tree::DominatorTree;
14use crate::dominator_tree::DominatorTreePreorder;
15use crate::egraph::EgraphPass;
16use crate::flowgraph::ControlFlowGraph;
17use crate::inline::{Inline, do_inlining};
18use crate::ir::Function;
19use crate::isa::TargetIsa;
20use crate::legalizer::simple_legalize;
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::trace;
28use crate::unreachable_code::eliminate_unreachable_code;
29use crate::verifier::{VerifierErrors, VerifierResult, verify_context};
30use crate::{CompileError, timing};
31#[cfg(feature = "souper-harvest")]
32use alloc::string::String;
33use alloc::vec::Vec;
34use cranelift_control::ControlPlane;
35use target_lexicon::Architecture;
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 domtree_preorder: DominatorTreePreorder,
53
54 pub loop_analysis: LoopAnalysis,
56
57 pub(crate) compiled_code: Option<CompiledCode>,
59
60 pub want_disasm: bool,
62}
63
64impl Context {
65 pub fn new() -> Self {
70 Self::for_function(Function::new())
71 }
72
73 pub fn for_function(func: Function) -> Self {
78 Self {
79 func,
80 cfg: ControlFlowGraph::new(),
81 domtree: DominatorTree::new(),
82 domtree_preorder: DominatorTreePreorder::new(),
83 loop_analysis: LoopAnalysis::new(),
84 compiled_code: None,
85 want_disasm: false,
86 }
87 }
88
89 pub fn clear(&mut self) {
91 self.func.clear();
92 self.cfg.clear();
93 self.domtree.clear();
94 self.loop_analysis.clear();
95 self.compiled_code = None;
96 self.want_disasm = false;
97 }
98
99 pub fn compiled_code(&self) -> Option<&CompiledCode> {
102 self.compiled_code.as_ref()
103 }
104
105 pub fn take_compiled_code(&mut self) -> Option<CompiledCode> {
108 self.compiled_code.take()
109 }
110
111 pub fn set_disasm(&mut self, val: bool) {
114 self.want_disasm = val;
115 }
116
117 #[deprecated = "use Context::compile"]
119 pub fn compile_and_emit(
120 &mut self,
121 isa: &dyn TargetIsa,
122 mem: &mut Vec<u8>,
123 ctrl_plane: &mut ControlPlane,
124 ) -> CompileResult<'_, &CompiledCode> {
125 let compiled_code = self.compile(isa, ctrl_plane)?;
126 mem.extend_from_slice(compiled_code.code_buffer());
127 Ok(compiled_code)
128 }
129
130 pub fn compile_stencil(
134 &mut self,
135 isa: &dyn TargetIsa,
136 ctrl_plane: &mut ControlPlane,
137 ) -> CodegenResult<CompiledCodeStencil> {
138 let result;
139 trace!("****** START compiling {}", self.func.display_spec());
140 {
141 let _tt = timing::compile();
142
143 self.verify_if(isa)?;
144 self.optimize(isa, ctrl_plane)?;
145 result = isa.compile_function(&self.func, &self.domtree, self.want_disasm, ctrl_plane);
146 }
147 trace!("****** DONE compiling {}\n", self.func.display_spec());
148 result
149 }
150
151 pub fn optimize(
157 &mut self,
158 isa: &dyn TargetIsa,
159 ctrl_plane: &mut ControlPlane,
160 ) -> CodegenResult<()> {
161 log::debug!(
162 "Number of CLIF instructions to optimize: {}",
163 self.func.dfg.num_insts()
164 );
165 log::debug!(
166 "Number of CLIF blocks to optimize: {}",
167 self.func.dfg.num_blocks()
168 );
169
170 let opt_level = isa.flags().opt_level();
171 crate::trace!(
172 "Optimizing (opt level {:?}):\n{}",
173 opt_level,
174 self.func.display()
175 );
176
177 if isa.flags().enable_nan_canonicalization() {
178 self.canonicalize_nans(isa)?;
179 }
180
181 self.legalize(isa)?;
182
183 self.compute_cfg();
184 self.compute_domtree();
185 self.eliminate_unreachable_code(isa)?;
186 self.remove_constant_phis(isa)?;
187
188 self.func.dfg.resolve_all_aliases();
189
190 if opt_level != OptLevel::None {
191 self.egraph_pass(isa, ctrl_plane)?;
192 }
193
194 Ok(())
195 }
196
197 pub fn inline(&mut self, inliner: impl Inline) -> CodegenResult<bool> {
201 do_inlining(&mut self.func, inliner)
202 }
203
204 pub fn compile(
217 &mut self,
218 isa: &dyn TargetIsa,
219 ctrl_plane: &mut ControlPlane,
220 ) -> CompileResult<'_, &CompiledCode> {
221 let stencil = self
222 .compile_stencil(isa, ctrl_plane)
223 .map_err(|error| CompileError {
224 inner: error,
225 func: &self.func,
226 })?;
227 Ok(self
228 .compiled_code
229 .insert(stencil.apply_params(&self.func.params)))
230 }
231
232 #[deprecated = "use CompiledCode::get_code_bb_layout"]
236 pub fn get_code_bb_layout(&self) -> Option<(Vec<usize>, Vec<(usize, usize)>)> {
237 self.compiled_code().map(CompiledCode::get_code_bb_layout)
238 }
239
240 #[cfg(feature = "unwind")]
244 #[deprecated = "use CompiledCode::create_unwind_info"]
245 pub fn create_unwind_info(
246 &self,
247 isa: &dyn TargetIsa,
248 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
249 self.compiled_code().unwrap().create_unwind_info(isa)
250 }
251
252 pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> {
258 let mut errors = VerifierErrors::default();
259 let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors);
260
261 if errors.is_empty() {
262 Ok(())
263 } else {
264 Err(errors)
265 }
266 }
267
268 pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> {
270 let fisa = fisa.into();
271 if fisa.flags.enable_verifier() {
272 self.verify(fisa)?;
273 }
274 Ok(())
275 }
276
277 pub fn remove_constant_phis<'a, FOI: Into<FlagsOrIsa<'a>>>(
279 &mut self,
280 fisa: FOI,
281 ) -> CodegenResult<()> {
282 do_remove_constant_phis(&mut self.func, &mut self.domtree);
283 self.verify_if(fisa)?;
284 Ok(())
285 }
286
287 pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
289 let has_vector_support = match isa.triple().architecture {
291 Architecture::Riscv64(_) => match isa.isa_flags().iter().find(|f| f.name == "has_v") {
292 Some(value) => value.as_bool().unwrap_or(false),
293 None => false,
294 },
295 _ => true,
296 };
297 do_nan_canonicalization(&mut self.func, has_vector_support);
298 self.verify_if(isa)
299 }
300
301 pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
303 self.domtree.clear();
306 self.loop_analysis.clear();
307 self.cfg.clear();
308
309 simple_legalize(&mut self.func, isa);
311 self.verify_if(isa)
312 }
313
314 pub fn compute_cfg(&mut self) {
316 self.cfg.compute(&self.func)
317 }
318
319 pub fn compute_domtree(&mut self) {
321 self.domtree.compute(&self.func, &self.cfg);
322 self.domtree_preorder.compute(&self.domtree);
323 }
324
325 pub fn compute_loop_analysis(&mut self) {
327 self.loop_analysis
328 .compute(&self.func, &self.cfg, &self.domtree)
329 }
330
331 pub fn flowgraph(&mut self) {
333 self.compute_cfg();
334 self.compute_domtree()
335 }
336
337 pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()>
339 where
340 FOI: Into<FlagsOrIsa<'a>>,
341 {
342 eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree);
343 self.verify_if(fisa)
344 }
345
346 pub fn replace_redundant_loads(&mut self) -> CodegenResult<()> {
352 let mut analysis = AliasAnalysis::new(&self.func, &self.domtree_preorder);
353 analysis.compute_and_update_aliases(&mut self.func);
354 Ok(())
355 }
356
357 #[cfg(feature = "souper-harvest")]
359 pub fn souper_harvest(
360 &mut self,
361 out: &mut std::sync::mpsc::Sender<String>,
362 ) -> CodegenResult<()> {
363 do_souper_harvest(&self.func, out);
364 Ok(())
365 }
366
367 pub fn egraph_pass<'a, FOI>(
369 &mut self,
370 fisa: FOI,
371 ctrl_plane: &mut ControlPlane,
372 ) -> CodegenResult<()>
373 where
374 FOI: Into<FlagsOrIsa<'a>>,
375 {
376 let _tt = timing::egraph();
377
378 trace!(
379 "About to optimize with egraph phase:\n{}",
380 self.func.display()
381 );
382 let fisa = fisa.into();
383 self.compute_loop_analysis();
384 let mut alias_analysis = AliasAnalysis::new(&self.func, &self.domtree_preorder);
385 let mut pass = EgraphPass::new(
386 &mut self.func,
387 &self.domtree,
388 &self.loop_analysis,
389 &mut alias_analysis,
390 &fisa.flags,
391 ctrl_plane,
392 );
393 pass.run();
394 log::debug!("egraph stats: {:?}", pass.stats);
395 trace!("After egraph optimization:\n{}", self.func.display());
396
397 self.verify_if(fisa)
398 }
399}