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::ir::Function;
18use crate::isa::TargetIsa;
19use crate::legalizer::simple_legalize;
20use crate::loop_analysis::LoopAnalysis;
21use crate::machinst::{CompiledCode, CompiledCodeStencil};
22use crate::nan_canonicalization::do_nan_canonicalization;
23use crate::remove_constant_phis::do_remove_constant_phis;
24use crate::result::{CodegenResult, CompileResult};
25use crate::settings::{FlagsOrIsa, OptLevel};
26use crate::trace;
27use crate::unreachable_code::eliminate_unreachable_code;
28use crate::verifier::{VerifierErrors, VerifierResult, verify_context};
29use crate::{CompileError, timing};
30#[cfg(feature = "souper-harvest")]
31use alloc::string::String;
32use alloc::vec::Vec;
33use cranelift_control::ControlPlane;
34use target_lexicon::Architecture;
35
36#[cfg(feature = "souper-harvest")]
37use crate::souper_harvest::do_souper_harvest;
38
39pub struct Context {
41 pub func: Function,
43
44 pub cfg: ControlFlowGraph,
46
47 pub domtree: DominatorTree,
49
50 domtree_preorder: DominatorTreePreorder,
52
53 pub loop_analysis: LoopAnalysis,
55
56 pub(crate) compiled_code: Option<CompiledCode>,
58
59 pub want_disasm: bool,
61}
62
63impl Context {
64 pub fn new() -> Self {
69 Self::for_function(Function::new())
70 }
71
72 pub fn for_function(func: Function) -> Self {
77 Self {
78 func,
79 cfg: ControlFlowGraph::new(),
80 domtree: DominatorTree::new(),
81 domtree_preorder: DominatorTreePreorder::new(),
82 loop_analysis: LoopAnalysis::new(),
83 compiled_code: None,
84 want_disasm: false,
85 }
86 }
87
88 pub fn clear(&mut self) {
90 self.func.clear();
91 self.cfg.clear();
92 self.domtree.clear();
93 self.loop_analysis.clear();
94 self.compiled_code = None;
95 self.want_disasm = false;
96 }
97
98 pub fn compiled_code(&self) -> Option<&CompiledCode> {
101 self.compiled_code.as_ref()
102 }
103
104 pub fn take_compiled_code(&mut self) -> Option<CompiledCode> {
107 self.compiled_code.take()
108 }
109
110 pub fn set_disasm(&mut self, val: bool) {
113 self.want_disasm = val;
114 }
115
116 #[deprecated = "use Context::compile"]
118 pub fn compile_and_emit(
119 &mut self,
120 isa: &dyn TargetIsa,
121 mem: &mut Vec<u8>,
122 ctrl_plane: &mut ControlPlane,
123 ) -> CompileResult<'_, &CompiledCode> {
124 let compiled_code = self.compile(isa, ctrl_plane)?;
125 mem.extend_from_slice(compiled_code.code_buffer());
126 Ok(compiled_code)
127 }
128
129 pub fn compile_stencil(
133 &mut self,
134 isa: &dyn TargetIsa,
135 ctrl_plane: &mut ControlPlane,
136 ) -> CodegenResult<CompiledCodeStencil> {
137 let result;
138 trace!("****** START compiling {}", self.func.display_spec());
139 {
140 let _tt = timing::compile();
141
142 self.verify_if(isa)?;
143 self.optimize(isa, ctrl_plane)?;
144 result = isa.compile_function(&self.func, &self.domtree, self.want_disasm, ctrl_plane);
145 }
146 trace!("****** DONE compiling {}\n", self.func.display_spec());
147 result
148 }
149
150 pub fn optimize(
156 &mut self,
157 isa: &dyn TargetIsa,
158 ctrl_plane: &mut ControlPlane,
159 ) -> CodegenResult<()> {
160 log::debug!(
161 "Number of CLIF instructions to optimize: {}",
162 self.func.dfg.num_insts()
163 );
164 log::debug!(
165 "Number of CLIF blocks to optimize: {}",
166 self.func.dfg.num_blocks()
167 );
168
169 let opt_level = isa.flags().opt_level();
170 crate::trace!(
171 "Optimizing (opt level {:?}):\n{}",
172 opt_level,
173 self.func.display()
174 );
175
176 if isa.flags().enable_nan_canonicalization() {
177 self.canonicalize_nans(isa)?;
178 }
179
180 self.legalize(isa)?;
181
182 self.compute_cfg();
183 self.compute_domtree();
184 self.eliminate_unreachable_code(isa)?;
185 self.remove_constant_phis(isa)?;
186
187 self.func.dfg.resolve_all_aliases();
188
189 if opt_level != OptLevel::None {
190 self.egraph_pass(isa, ctrl_plane)?;
191 }
192
193 Ok(())
194 }
195
196 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 self.cfg.clear();
300
301 simple_legalize(&mut self.func, isa);
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 self.domtree_preorder.compute(&self.domtree);
315 }
316
317 pub fn compute_loop_analysis(&mut self) {
319 self.loop_analysis
320 .compute(&self.func, &self.cfg, &self.domtree)
321 }
322
323 pub fn flowgraph(&mut self) {
325 self.compute_cfg();
326 self.compute_domtree()
327 }
328
329 pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()>
331 where
332 FOI: Into<FlagsOrIsa<'a>>,
333 {
334 eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree);
335 self.verify_if(fisa)
336 }
337
338 pub fn replace_redundant_loads(&mut self) -> CodegenResult<()> {
344 let mut analysis = AliasAnalysis::new(&self.func, &self.domtree_preorder);
345 analysis.compute_and_update_aliases(&mut self.func);
346 Ok(())
347 }
348
349 #[cfg(feature = "souper-harvest")]
351 pub fn souper_harvest(
352 &mut self,
353 out: &mut std::sync::mpsc::Sender<String>,
354 ) -> CodegenResult<()> {
355 do_souper_harvest(&self.func, out);
356 Ok(())
357 }
358
359 pub fn egraph_pass<'a, FOI>(
361 &mut self,
362 fisa: FOI,
363 ctrl_plane: &mut ControlPlane,
364 ) -> CodegenResult<()>
365 where
366 FOI: Into<FlagsOrIsa<'a>>,
367 {
368 let _tt = timing::egraph();
369
370 trace!(
371 "About to optimize with egraph phase:\n{}",
372 self.func.display()
373 );
374 let fisa = fisa.into();
375 self.compute_loop_analysis();
376 let mut alias_analysis = AliasAnalysis::new(&self.func, &self.domtree_preorder);
377 let mut pass = EgraphPass::new(
378 &mut self.func,
379 &self.domtree,
380 &self.loop_analysis,
381 &mut alias_analysis,
382 &fisa.flags,
383 ctrl_plane,
384 );
385 pass.run();
386 log::debug!("egraph stats: {:?}", pass.stats);
387 trace!("After egraph optimization:\n{}", self.func.display());
388
389 self.verify_if(fisa)
390 }
391}