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
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 #[deprecated = "use Context::compile"]
113 pub fn compile_and_emit(
114 &mut self,
115 isa: &dyn TargetIsa,
116 mem: &mut Vec<u8>,
117 ctrl_plane: &mut ControlPlane,
118 ) -> CompileResult<'_, &CompiledCode> {
119 let compiled_code = self.compile(isa, ctrl_plane)?;
120 mem.extend_from_slice(compiled_code.code_buffer());
121 Ok(compiled_code)
122 }
123
124 pub fn compile_stencil(
128 &mut self,
129 isa: &dyn TargetIsa,
130 ctrl_plane: &mut ControlPlane,
131 ) -> CodegenResult<CompiledCodeStencil> {
132 let result;
133 trace!("****** START compiling {}", self.func.display_spec());
134 {
135 let _tt = timing::compile();
136
137 self.verify_if(isa)?;
138 self.optimize(isa, ctrl_plane)?;
139 result = isa.compile_function(&self.func, &self.domtree, self.want_disasm, ctrl_plane);
140 }
141 trace!("****** DONE compiling {}\n", self.func.display_spec());
142 result
143 }
144
145 pub fn optimize(
151 &mut self,
152 isa: &dyn TargetIsa,
153 ctrl_plane: &mut ControlPlane,
154 ) -> CodegenResult<()> {
155 log::debug!(
156 "Number of CLIF instructions to optimize: {}",
157 self.func.dfg.num_insts()
158 );
159 log::debug!(
160 "Number of CLIF blocks to optimize: {}",
161 self.func.dfg.num_blocks()
162 );
163
164 let opt_level = isa.flags().opt_level();
165 crate::trace!(
166 "Optimizing (opt level {:?}):\n{}",
167 opt_level,
168 self.func.display()
169 );
170
171 if isa.flags().enable_nan_canonicalization() {
172 self.canonicalize_nans(isa)?;
173 }
174
175 self.verify_if(isa)?;
176
177 self.compute_cfg();
178 self.compute_domtree();
179 self.eliminate_unreachable_code(isa)?;
180 self.remove_constant_phis(isa)?;
181
182 self.func.dfg.resolve_all_aliases();
183
184 if opt_level != OptLevel::None {
185 self.egraph_pass(isa, ctrl_plane)?;
186 }
187
188 Ok(())
189 }
190
191 pub fn inline(&mut self, inliner: impl Inline) -> CodegenResult<bool> {
195 do_inlining(&mut self.func, inliner)
196 }
197
198 pub fn compile(
211 &mut self,
212 isa: &dyn TargetIsa,
213 ctrl_plane: &mut ControlPlane,
214 ) -> CompileResult<'_, &CompiledCode> {
215 let stencil = self
216 .compile_stencil(isa, ctrl_plane)
217 .map_err(|error| CompileError {
218 inner: error,
219 func: &self.func,
220 })?;
221 Ok(self
222 .compiled_code
223 .insert(stencil.apply_params(&self.func.params)))
224 }
225
226 #[deprecated = "use CompiledCode::get_code_bb_layout"]
230 pub fn get_code_bb_layout(&self) -> Option<(Vec<usize>, Vec<(usize, usize)>)> {
231 self.compiled_code().map(CompiledCode::get_code_bb_layout)
232 }
233
234 #[cfg(feature = "unwind")]
238 #[deprecated = "use CompiledCode::create_unwind_info"]
239 pub fn create_unwind_info(
240 &self,
241 isa: &dyn TargetIsa,
242 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
243 self.compiled_code().unwrap().create_unwind_info(isa)
244 }
245
246 pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> {
252 let mut errors = VerifierErrors::default();
253 let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors);
254
255 if errors.is_empty() {
256 Ok(())
257 } else {
258 Err(errors)
259 }
260 }
261
262 pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> {
264 let fisa = fisa.into();
265 if fisa.flags.enable_verifier() {
266 self.verify(fisa)?;
267 }
268 Ok(())
269 }
270
271 pub fn remove_constant_phis<'a, FOI: Into<FlagsOrIsa<'a>>>(
273 &mut self,
274 fisa: FOI,
275 ) -> CodegenResult<()> {
276 do_remove_constant_phis(&mut self.func, &mut self.domtree);
277 self.verify_if(fisa)?;
278 Ok(())
279 }
280
281 pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
283 let has_vector_support = match isa.triple().architecture {
285 Architecture::Riscv64(_) => match isa.isa_flags().iter().find(|f| f.name == "has_v") {
286 Some(value) => value.as_bool().unwrap_or(false),
287 None => false,
288 },
289 _ => true,
290 };
291 do_nan_canonicalization(&mut self.func, has_vector_support);
292 self.verify_if(isa)
293 }
294
295 pub fn compute_cfg(&mut self) {
297 self.cfg.compute(&self.func)
298 }
299
300 pub fn compute_domtree(&mut self) {
302 self.domtree.compute(&self.func, &self.cfg);
303 }
304
305 pub fn compute_loop_analysis(&mut self) {
307 self.loop_analysis
308 .compute(&self.func, &self.cfg, &self.domtree)
309 }
310
311 pub fn flowgraph(&mut self) {
313 self.compute_cfg();
314 self.compute_domtree()
315 }
316
317 pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()>
319 where
320 FOI: Into<FlagsOrIsa<'a>>,
321 {
322 let domtree = &self.domtree;
323 eliminate_unreachable_code(&mut self.func, &mut self.cfg, |block| {
324 domtree.is_reachable(block)
325 });
326 self.verify_if(fisa)
327 }
328
329 pub fn replace_redundant_loads(&mut self) -> CodegenResult<()> {
335 let mut analysis = AliasAnalysis::new(&self.func, &self.domtree);
336 analysis.compute_and_update_aliases(&mut self.func);
337 Ok(())
338 }
339
340 #[cfg(feature = "souper-harvest")]
342 pub fn souper_harvest(
343 &mut self,
344 out: &mut std::sync::mpsc::Sender<String>,
345 ) -> CodegenResult<()> {
346 do_souper_harvest(&self.func, out);
347 Ok(())
348 }
349
350 pub fn egraph_pass<'a, FOI>(
352 &mut self,
353 fisa: FOI,
354 ctrl_plane: &mut ControlPlane,
355 ) -> CodegenResult<()>
356 where
357 FOI: Into<FlagsOrIsa<'a>>,
358 {
359 let _tt = timing::egraph();
360
361 trace!(
362 "About to optimize with egraph phase:\n{}",
363 self.func.display()
364 );
365 let fisa = fisa.into();
366 self.compute_loop_analysis();
367 let mut alias_analysis = AliasAnalysis::new(&self.func, &self.domtree);
368 let mut pass = EgraphPass::new(
369 &mut self.func,
370 &self.domtree,
371 &self.loop_analysis,
372 &mut alias_analysis,
373 ctrl_plane,
374 &mut self.cfg,
375 );
376 pass.run();
377 log::debug!("egraph stats: {:?}", pass.stats);
378 trace!("After egraph optimization:\n{}", self.func.display());
379
380 self.compute_cfg();
382 self.compute_domtree();
383
384 self.verify_if(fisa)?;
385
386 Ok(())
387 }
388}