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::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 pub loop_analysis: LoopAnalysis,
52
53 pub(crate) compiled_code: Option<CompiledCode>,
55
56 pub want_disasm: bool,
58}
59
60impl Context {
61 pub fn new() -> Self {
66 Self::for_function(Function::new())
67 }
68
69 pub fn for_function(func: Function) -> Self {
74 Self {
75 func,
76 cfg: ControlFlowGraph::new(),
77 domtree: DominatorTree::new(),
78 loop_analysis: LoopAnalysis::new(),
79 compiled_code: None,
80 want_disasm: false,
81 }
82 }
83
84 pub fn clear(&mut self) {
86 self.func.clear();
87 self.cfg.clear();
88 self.domtree.clear();
89 self.loop_analysis.clear();
90 self.compiled_code = None;
91 self.want_disasm = false;
92 }
93
94 pub fn compiled_code(&self) -> Option<&CompiledCode> {
97 self.compiled_code.as_ref()
98 }
99
100 pub fn take_compiled_code(&mut self) -> Option<CompiledCode> {
103 self.compiled_code.take()
104 }
105
106 pub fn set_disasm(&mut self, val: bool) {
109 self.want_disasm = val;
110 }
111
112 #[deprecated = "use Context::compile"]
114 pub fn compile_and_emit(
115 &mut self,
116 isa: &dyn TargetIsa,
117 mem: &mut Vec<u8>,
118 ctrl_plane: &mut ControlPlane,
119 ) -> CompileResult<'_, &CompiledCode> {
120 let compiled_code = self.compile(isa, ctrl_plane)?;
121 mem.extend_from_slice(compiled_code.code_buffer());
122 Ok(compiled_code)
123 }
124
125 pub fn compile_stencil(
129 &mut self,
130 isa: &dyn TargetIsa,
131 ctrl_plane: &mut ControlPlane,
132 ) -> CodegenResult<CompiledCodeStencil> {
133 let result;
134 trace!("****** START compiling {}", self.func.display_spec());
135 {
136 let _tt = timing::compile();
137
138 self.verify_if(isa)?;
139 self.optimize(isa, ctrl_plane)?;
140 result = isa.compile_function(&self.func, &self.domtree, self.want_disasm, ctrl_plane);
141 }
142 trace!("****** DONE compiling {}\n", self.func.display_spec());
143 result
144 }
145
146 pub fn optimize(
152 &mut self,
153 isa: &dyn TargetIsa,
154 ctrl_plane: &mut ControlPlane,
155 ) -> CodegenResult<()> {
156 log::debug!(
157 "Number of CLIF instructions to optimize: {}",
158 self.func.dfg.num_insts()
159 );
160 log::debug!(
161 "Number of CLIF blocks to optimize: {}",
162 self.func.dfg.num_blocks()
163 );
164
165 let opt_level = isa.flags().opt_level();
166 crate::trace!(
167 "Optimizing (opt level {:?}):\n{}",
168 opt_level,
169 self.func.display()
170 );
171
172 if isa.flags().enable_nan_canonicalization() {
173 self.canonicalize_nans(isa)?;
174 }
175
176 self.legalize(isa)?;
177
178 self.compute_cfg();
179 self.compute_domtree();
180 self.eliminate_unreachable_code(isa)?;
181 self.remove_constant_phis(isa)?;
182
183 self.func.dfg.resolve_all_aliases();
184
185 if opt_level != OptLevel::None {
186 self.egraph_pass(isa, ctrl_plane)?;
187 }
188
189 Ok(())
190 }
191
192 pub fn inline(&mut self, inliner: impl Inline) -> CodegenResult<bool> {
196 do_inlining(&mut self.func, inliner)
197 }
198
199 pub fn compile(
212 &mut self,
213 isa: &dyn TargetIsa,
214 ctrl_plane: &mut ControlPlane,
215 ) -> CompileResult<'_, &CompiledCode> {
216 let stencil = self
217 .compile_stencil(isa, ctrl_plane)
218 .map_err(|error| CompileError {
219 inner: error,
220 func: &self.func,
221 })?;
222 Ok(self
223 .compiled_code
224 .insert(stencil.apply_params(&self.func.params)))
225 }
226
227 #[deprecated = "use CompiledCode::get_code_bb_layout"]
231 pub fn get_code_bb_layout(&self) -> Option<(Vec<usize>, Vec<(usize, usize)>)> {
232 self.compiled_code().map(CompiledCode::get_code_bb_layout)
233 }
234
235 #[cfg(feature = "unwind")]
239 #[deprecated = "use CompiledCode::create_unwind_info"]
240 pub fn create_unwind_info(
241 &self,
242 isa: &dyn TargetIsa,
243 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
244 self.compiled_code().unwrap().create_unwind_info(isa)
245 }
246
247 pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> {
253 let mut errors = VerifierErrors::default();
254 let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors);
255
256 if errors.is_empty() {
257 Ok(())
258 } else {
259 Err(errors)
260 }
261 }
262
263 pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> {
265 let fisa = fisa.into();
266 if fisa.flags.enable_verifier() {
267 self.verify(fisa)?;
268 }
269 Ok(())
270 }
271
272 pub fn remove_constant_phis<'a, FOI: Into<FlagsOrIsa<'a>>>(
274 &mut self,
275 fisa: FOI,
276 ) -> CodegenResult<()> {
277 do_remove_constant_phis(&mut self.func, &mut self.domtree);
278 self.verify_if(fisa)?;
279 Ok(())
280 }
281
282 pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
284 let has_vector_support = match isa.triple().architecture {
286 Architecture::Riscv64(_) => match isa.isa_flags().iter().find(|f| f.name == "has_v") {
287 Some(value) => value.as_bool().unwrap_or(false),
288 None => false,
289 },
290 _ => true,
291 };
292 do_nan_canonicalization(&mut self.func, has_vector_support);
293 self.verify_if(isa)
294 }
295
296 pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
298 self.domtree.clear();
301 self.loop_analysis.clear();
302 self.cfg.clear();
303
304 simple_legalize(&mut self.func, isa);
306 self.verify_if(isa)
307 }
308
309 pub fn compute_cfg(&mut self) {
311 self.cfg.compute(&self.func)
312 }
313
314 pub fn compute_domtree(&mut self) {
316 self.domtree.compute(&self.func, &self.cfg);
317 }
318
319 pub fn compute_loop_analysis(&mut self) {
321 self.loop_analysis
322 .compute(&self.func, &self.cfg, &self.domtree)
323 }
324
325 pub fn flowgraph(&mut self) {
327 self.compute_cfg();
328 self.compute_domtree()
329 }
330
331 pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()>
333 where
334 FOI: Into<FlagsOrIsa<'a>>,
335 {
336 eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree);
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);
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 &fisa.flags,
385 ctrl_plane,
386 );
387 pass.run();
388 log::debug!("egraph stats: {:?}", pass.stats);
389 trace!("After egraph optimization:\n{}", self.func.display());
390
391 self.verify_if(fisa)
392 }
393}