/rust/registry/src/index.crates.io-1949cf8c6b5b557f/cranelift-codegen-0.129.1/src/context.rs
Line | Count | Source |
1 | | //! Cranelift compilation context and main entry point. |
2 | | //! |
3 | | //! When compiling many small functions, it is important to avoid repeatedly allocating and |
4 | | //! deallocating the data structures needed for compilation. The `Context` struct is used to hold |
5 | | //! on to memory allocations between function compilations. |
6 | | //! |
7 | | //! The context does not hold a `TargetIsa` instance which has to be provided as an argument |
8 | | //! instead. This is because an ISA instance is immutable and can be used by multiple compilation |
9 | | //! contexts concurrently. Typically, you would have one context per compilation thread and only a |
10 | | //! single ISA instance. |
11 | | |
12 | | use crate::alias_analysis::AliasAnalysis; |
13 | | use crate::dominator_tree::DominatorTree; |
14 | | use crate::egraph::EgraphPass; |
15 | | use crate::flowgraph::ControlFlowGraph; |
16 | | use crate::inline::{Inline, do_inlining}; |
17 | | use crate::ir::Function; |
18 | | use crate::isa::TargetIsa; |
19 | | use crate::legalizer::simple_legalize; |
20 | | use crate::loop_analysis::LoopAnalysis; |
21 | | use crate::machinst::{CompiledCode, CompiledCodeStencil}; |
22 | | use crate::nan_canonicalization::do_nan_canonicalization; |
23 | | use crate::remove_constant_phis::do_remove_constant_phis; |
24 | | use crate::result::{CodegenResult, CompileResult}; |
25 | | use crate::settings::{FlagsOrIsa, OptLevel}; |
26 | | use crate::trace; |
27 | | use crate::unreachable_code::eliminate_unreachable_code; |
28 | | use crate::verifier::{VerifierErrors, VerifierResult, verify_context}; |
29 | | use crate::{CompileError, timing}; |
30 | | #[cfg(feature = "souper-harvest")] |
31 | | use alloc::string::String; |
32 | | use alloc::vec::Vec; |
33 | | use cranelift_control::ControlPlane; |
34 | | use target_lexicon::Architecture; |
35 | | |
36 | | #[cfg(feature = "souper-harvest")] |
37 | | use crate::souper_harvest::do_souper_harvest; |
38 | | |
39 | | /// Persistent data structures and compilation pipeline. |
40 | | pub struct Context { |
41 | | /// The function we're compiling. |
42 | | pub func: Function, |
43 | | |
44 | | /// The control flow graph of `func`. |
45 | | pub cfg: ControlFlowGraph, |
46 | | |
47 | | /// Dominator tree for `func`. |
48 | | pub domtree: DominatorTree, |
49 | | |
50 | | /// Loop analysis of `func`. |
51 | | pub loop_analysis: LoopAnalysis, |
52 | | |
53 | | /// Result of MachBackend compilation, if computed. |
54 | | pub(crate) compiled_code: Option<CompiledCode>, |
55 | | |
56 | | /// Flag: do we want a disassembly with the CompiledCode? |
57 | | pub want_disasm: bool, |
58 | | } |
59 | | |
60 | | impl Context { |
61 | | /// Allocate a new compilation context. |
62 | | /// |
63 | | /// The returned instance should be reused for compiling multiple functions in order to avoid |
64 | | /// needless allocator thrashing. |
65 | 198k | pub fn new() -> Self { |
66 | 198k | Self::for_function(Function::new()) |
67 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::new <cranelift_codegen::context::Context>::new Line | Count | Source | 65 | 198k | pub fn new() -> Self { | 66 | 198k | Self::for_function(Function::new()) | 67 | 198k | } |
|
68 | | |
69 | | /// Allocate a new compilation context with an existing Function. |
70 | | /// |
71 | | /// The returned instance should be reused for compiling multiple functions in order to avoid |
72 | | /// needless allocator thrashing. |
73 | 198k | pub fn for_function(func: Function) -> Self { |
74 | 198k | Self { |
75 | 198k | func, |
76 | 198k | cfg: ControlFlowGraph::new(), |
77 | 198k | domtree: DominatorTree::new(), |
78 | 198k | loop_analysis: LoopAnalysis::new(), |
79 | 198k | compiled_code: None, |
80 | 198k | want_disasm: false, |
81 | 198k | } |
82 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::for_function <cranelift_codegen::context::Context>::for_function Line | Count | Source | 73 | 198k | pub fn for_function(func: Function) -> Self { | 74 | 198k | Self { | 75 | 198k | func, | 76 | 198k | cfg: ControlFlowGraph::new(), | 77 | 198k | domtree: DominatorTree::new(), | 78 | 198k | loop_analysis: LoopAnalysis::new(), | 79 | 198k | compiled_code: None, | 80 | 198k | want_disasm: false, | 81 | 198k | } | 82 | 198k | } |
|
83 | | |
84 | | /// Clear all data structures in this context. |
85 | 0 | pub fn clear(&mut self) { |
86 | 0 | self.func.clear(); |
87 | 0 | self.cfg.clear(); |
88 | 0 | self.domtree.clear(); |
89 | 0 | self.loop_analysis.clear(); |
90 | 0 | self.compiled_code = None; |
91 | 0 | self.want_disasm = false; |
92 | 0 | } Unexecuted instantiation: <cranelift_codegen::context::Context>::clear Unexecuted instantiation: <cranelift_codegen::context::Context>::clear |
93 | | |
94 | | /// Returns the compilation result for this function, available after any `compile` function |
95 | | /// has been called. |
96 | 318k | pub fn compiled_code(&self) -> Option<&CompiledCode> { |
97 | 318k | self.compiled_code.as_ref() |
98 | 318k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::compiled_code <cranelift_codegen::context::Context>::compiled_code Line | Count | Source | 96 | 318k | pub fn compiled_code(&self) -> Option<&CompiledCode> { | 97 | 318k | self.compiled_code.as_ref() | 98 | 318k | } |
|
99 | | |
100 | | /// Returns the compilation result for this function, available after any `compile` function |
101 | | /// has been called. |
102 | 0 | pub fn take_compiled_code(&mut self) -> Option<CompiledCode> { |
103 | 0 | self.compiled_code.take() |
104 | 0 | } Unexecuted instantiation: <cranelift_codegen::context::Context>::take_compiled_code Unexecuted instantiation: <cranelift_codegen::context::Context>::take_compiled_code |
105 | | |
106 | | /// Set the flag to request a disassembly when compiling with a |
107 | | /// `MachBackend` backend. |
108 | 0 | pub fn set_disasm(&mut self, val: bool) { |
109 | 0 | self.want_disasm = val; |
110 | 0 | } Unexecuted instantiation: <cranelift_codegen::context::Context>::set_disasm Unexecuted instantiation: <cranelift_codegen::context::Context>::set_disasm |
111 | | |
112 | | /// Compile the function, and emit machine code into a `Vec<u8>`. |
113 | | #[deprecated = "use Context::compile"] |
114 | 0 | pub fn compile_and_emit( |
115 | 0 | &mut self, |
116 | 0 | isa: &dyn TargetIsa, |
117 | 0 | mem: &mut Vec<u8>, |
118 | 0 | ctrl_plane: &mut ControlPlane, |
119 | 0 | ) -> CompileResult<'_, &CompiledCode> { |
120 | 0 | let compiled_code = self.compile(isa, ctrl_plane)?; |
121 | 0 | mem.extend_from_slice(compiled_code.code_buffer()); |
122 | 0 | Ok(compiled_code) |
123 | 0 | } Unexecuted instantiation: <cranelift_codegen::context::Context>::compile_and_emit Unexecuted instantiation: <cranelift_codegen::context::Context>::compile_and_emit |
124 | | |
125 | | /// Internally compiles the function into a stencil. |
126 | | /// |
127 | | /// Public only for testing and fuzzing purposes. |
128 | 198k | pub fn compile_stencil( |
129 | 198k | &mut self, |
130 | 198k | isa: &dyn TargetIsa, |
131 | 198k | ctrl_plane: &mut ControlPlane, |
132 | 198k | ) -> CodegenResult<CompiledCodeStencil> { |
133 | | let result; |
134 | 198k | trace!("****** START compiling {}", self.func.display_spec()); |
135 | | { |
136 | 198k | let _tt = timing::compile(); |
137 | | |
138 | 198k | self.verify_if(isa)?; |
139 | 198k | self.optimize(isa, ctrl_plane)?; |
140 | 198k | result = isa.compile_function(&self.func, &self.domtree, self.want_disasm, ctrl_plane); |
141 | | } |
142 | 198k | trace!("****** DONE compiling {}\n", self.func.display_spec()); |
143 | 198k | result |
144 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::compile_stencil <cranelift_codegen::context::Context>::compile_stencil Line | Count | Source | 128 | 198k | pub fn compile_stencil( | 129 | 198k | &mut self, | 130 | 198k | isa: &dyn TargetIsa, | 131 | 198k | ctrl_plane: &mut ControlPlane, | 132 | 198k | ) -> CodegenResult<CompiledCodeStencil> { | 133 | | let result; | 134 | 198k | trace!("****** START compiling {}", self.func.display_spec()); | 135 | | { | 136 | 198k | let _tt = timing::compile(); | 137 | | | 138 | 198k | self.verify_if(isa)?; | 139 | 198k | self.optimize(isa, ctrl_plane)?; | 140 | 198k | result = isa.compile_function(&self.func, &self.domtree, self.want_disasm, ctrl_plane); | 141 | | } | 142 | 198k | trace!("****** DONE compiling {}\n", self.func.display_spec()); | 143 | 198k | result | 144 | 198k | } |
|
145 | | |
146 | | /// Optimize the function, performing all compilation steps up to |
147 | | /// but not including machine-code lowering and register |
148 | | /// allocation. |
149 | | /// |
150 | | /// Public only for testing purposes. |
151 | 198k | pub fn optimize( |
152 | 198k | &mut self, |
153 | 198k | isa: &dyn TargetIsa, |
154 | 198k | ctrl_plane: &mut ControlPlane, |
155 | 198k | ) -> CodegenResult<()> { |
156 | 198k | log::debug!( |
157 | | "Number of CLIF instructions to optimize: {}", |
158 | 0 | self.func.dfg.num_insts() |
159 | | ); |
160 | 198k | log::debug!( |
161 | | "Number of CLIF blocks to optimize: {}", |
162 | 0 | self.func.dfg.num_blocks() |
163 | | ); |
164 | | |
165 | 198k | let opt_level = isa.flags().opt_level(); |
166 | 198k | crate::trace!( |
167 | | "Optimizing (opt level {:?}):\n{}", |
168 | | opt_level, |
169 | 0 | self.func.display() |
170 | | ); |
171 | | |
172 | 198k | if isa.flags().enable_nan_canonicalization() { |
173 | 198k | self.canonicalize_nans(isa)?; |
174 | 0 | } |
175 | | |
176 | 198k | self.legalize(isa)?; |
177 | | |
178 | 198k | self.compute_cfg(); |
179 | 198k | self.compute_domtree(); |
180 | 198k | self.eliminate_unreachable_code(isa)?; |
181 | 198k | self.remove_constant_phis(isa)?; |
182 | | |
183 | 198k | self.func.dfg.resolve_all_aliases(); |
184 | | |
185 | 198k | if opt_level != OptLevel::None { |
186 | 198k | self.egraph_pass(isa, ctrl_plane)?; |
187 | 0 | } |
188 | | |
189 | 198k | Ok(()) |
190 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::optimize <cranelift_codegen::context::Context>::optimize Line | Count | Source | 151 | 198k | pub fn optimize( | 152 | 198k | &mut self, | 153 | 198k | isa: &dyn TargetIsa, | 154 | 198k | ctrl_plane: &mut ControlPlane, | 155 | 198k | ) -> CodegenResult<()> { | 156 | 198k | log::debug!( | 157 | | "Number of CLIF instructions to optimize: {}", | 158 | 0 | self.func.dfg.num_insts() | 159 | | ); | 160 | 198k | log::debug!( | 161 | | "Number of CLIF blocks to optimize: {}", | 162 | 0 | self.func.dfg.num_blocks() | 163 | | ); | 164 | | | 165 | 198k | let opt_level = isa.flags().opt_level(); | 166 | 198k | crate::trace!( | 167 | | "Optimizing (opt level {:?}):\n{}", | 168 | | opt_level, | 169 | 0 | self.func.display() | 170 | | ); | 171 | | | 172 | 198k | if isa.flags().enable_nan_canonicalization() { | 173 | 198k | self.canonicalize_nans(isa)?; | 174 | 0 | } | 175 | | | 176 | 198k | self.legalize(isa)?; | 177 | | | 178 | 198k | self.compute_cfg(); | 179 | 198k | self.compute_domtree(); | 180 | 198k | self.eliminate_unreachable_code(isa)?; | 181 | 198k | self.remove_constant_phis(isa)?; | 182 | | | 183 | 198k | self.func.dfg.resolve_all_aliases(); | 184 | | | 185 | 198k | if opt_level != OptLevel::None { | 186 | 198k | self.egraph_pass(isa, ctrl_plane)?; | 187 | 0 | } | 188 | | | 189 | 198k | Ok(()) | 190 | 198k | } |
|
191 | | |
192 | | /// Perform function call inlining. |
193 | | /// |
194 | | /// Returns `true` if any function call was inlined, `false` otherwise. |
195 | 0 | pub fn inline(&mut self, inliner: impl Inline) -> CodegenResult<bool> { |
196 | 0 | do_inlining(&mut self.func, inliner) |
197 | 0 | } Unexecuted instantiation: <cranelift_codegen::context::Context>::inline::<_> Unexecuted instantiation: <cranelift_codegen::context::Context>::inline::<_> |
198 | | |
199 | | /// Compile the function, |
200 | | /// |
201 | | /// Run the function through all the passes necessary to generate |
202 | | /// code for the target ISA represented by `isa`. The generated |
203 | | /// machine code is not relocated. Instead, any relocations can be |
204 | | /// obtained from `compiled_code.buffer.relocs()`. |
205 | | /// |
206 | | /// Performs any optimizations that are enabled, unless |
207 | | /// `optimize()` was already invoked. |
208 | | /// |
209 | | /// Returns the generated machine code as well as information about |
210 | | /// the function's code and read-only data. |
211 | 198k | pub fn compile( |
212 | 198k | &mut self, |
213 | 198k | isa: &dyn TargetIsa, |
214 | 198k | ctrl_plane: &mut ControlPlane, |
215 | 198k | ) -> CompileResult<'_, &CompiledCode> { |
216 | 198k | let stencil = self |
217 | 198k | .compile_stencil(isa, ctrl_plane) |
218 | 198k | .map_err(|error| CompileError { |
219 | 0 | inner: error, |
220 | 0 | func: &self.func, |
221 | 0 | })?; Unexecuted instantiation: <cranelift_codegen::context::Context>::compile::{closure#0}Unexecuted instantiation: <cranelift_codegen::context::Context>::compile::{closure#0} |
222 | 198k | Ok(self |
223 | 198k | .compiled_code |
224 | 198k | .insert(stencil.apply_params(&self.func.params))) |
225 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::compile <cranelift_codegen::context::Context>::compile Line | Count | Source | 211 | 198k | pub fn compile( | 212 | 198k | &mut self, | 213 | 198k | isa: &dyn TargetIsa, | 214 | 198k | ctrl_plane: &mut ControlPlane, | 215 | 198k | ) -> CompileResult<'_, &CompiledCode> { | 216 | 198k | let stencil = self | 217 | 198k | .compile_stencil(isa, ctrl_plane) | 218 | 198k | .map_err(|error| CompileError { | 219 | | inner: error, | 220 | | func: &self.func, | 221 | 0 | })?; | 222 | 198k | Ok(self | 223 | 198k | .compiled_code | 224 | 198k | .insert(stencil.apply_params(&self.func.params))) | 225 | 198k | } |
|
226 | | |
227 | | /// If available, return information about the code layout in the |
228 | | /// final machine code: the offsets (in bytes) of each basic-block |
229 | | /// start, and all basic-block edges. |
230 | | #[deprecated = "use CompiledCode::get_code_bb_layout"] |
231 | 0 | pub fn get_code_bb_layout(&self) -> Option<(Vec<usize>, Vec<(usize, usize)>)> { |
232 | 0 | self.compiled_code().map(CompiledCode::get_code_bb_layout) |
233 | 0 | } Unexecuted instantiation: <cranelift_codegen::context::Context>::get_code_bb_layout Unexecuted instantiation: <cranelift_codegen::context::Context>::get_code_bb_layout |
234 | | |
235 | | /// Creates unwind information for the function. |
236 | | /// |
237 | | /// Returns `None` if the function has no unwind information. |
238 | | #[cfg(feature = "unwind")] |
239 | | #[deprecated = "use CompiledCode::create_unwind_info"] |
240 | 0 | pub fn create_unwind_info( |
241 | 0 | &self, |
242 | 0 | isa: &dyn TargetIsa, |
243 | 0 | ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> { |
244 | 0 | self.compiled_code().unwrap().create_unwind_info(isa) |
245 | 0 | } Unexecuted instantiation: <cranelift_codegen::context::Context>::create_unwind_info Unexecuted instantiation: <cranelift_codegen::context::Context>::create_unwind_info |
246 | | |
247 | | /// Run the verifier on the function. |
248 | | /// |
249 | | /// Also check that the dominator tree and control flow graph are consistent with the function. |
250 | | /// |
251 | | /// TODO: rename to "CLIF validate" or similar. |
252 | 1.19M | pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> { |
253 | 1.19M | let mut errors = VerifierErrors::default(); |
254 | 1.19M | let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors); |
255 | | |
256 | 1.19M | if errors.is_empty() { |
257 | 1.19M | Ok(()) |
258 | | } else { |
259 | 0 | Err(errors) |
260 | | } |
261 | 1.19M | } Unexecuted instantiation: <cranelift_codegen::context::Context>::verify::<cranelift_codegen::settings::FlagsOrIsa> <cranelift_codegen::context::Context>::verify::<cranelift_codegen::settings::FlagsOrIsa> Line | Count | Source | 252 | 1.19M | pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> { | 253 | 1.19M | let mut errors = VerifierErrors::default(); | 254 | 1.19M | let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors); | 255 | | | 256 | 1.19M | if errors.is_empty() { | 257 | 1.19M | Ok(()) | 258 | | } else { | 259 | 0 | Err(errors) | 260 | | } | 261 | 1.19M | } |
|
262 | | |
263 | | /// Run the verifier only if the `enable_verifier` setting is true. |
264 | 1.19M | pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> { |
265 | 1.19M | let fisa = fisa.into(); |
266 | 1.19M | if fisa.flags.enable_verifier() { |
267 | 1.19M | self.verify(fisa)?; |
268 | 0 | } |
269 | 1.19M | Ok(()) |
270 | 1.19M | } Unexecuted instantiation: <cranelift_codegen::context::Context>::verify_if::<cranelift_codegen::settings::FlagsOrIsa> Unexecuted instantiation: <cranelift_codegen::context::Context>::verify_if::<&dyn cranelift_codegen::isa::TargetIsa> <cranelift_codegen::context::Context>::verify_if::<cranelift_codegen::settings::FlagsOrIsa> Line | Count | Source | 264 | 198k | pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> { | 265 | 198k | let fisa = fisa.into(); | 266 | 198k | if fisa.flags.enable_verifier() { | 267 | 198k | self.verify(fisa)?; | 268 | 0 | } | 269 | 198k | Ok(()) | 270 | 198k | } |
<cranelift_codegen::context::Context>::verify_if::<&dyn cranelift_codegen::isa::TargetIsa> Line | Count | Source | 264 | 992k | pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> { | 265 | 992k | let fisa = fisa.into(); | 266 | 992k | if fisa.flags.enable_verifier() { | 267 | 992k | self.verify(fisa)?; | 268 | 0 | } | 269 | 992k | Ok(()) | 270 | 992k | } |
|
271 | | |
272 | | /// Perform constant-phi removal on the function. |
273 | 198k | pub fn remove_constant_phis<'a, FOI: Into<FlagsOrIsa<'a>>>( |
274 | 198k | &mut self, |
275 | 198k | fisa: FOI, |
276 | 198k | ) -> CodegenResult<()> { |
277 | 198k | do_remove_constant_phis(&mut self.func, &mut self.domtree); |
278 | 198k | self.verify_if(fisa)?; |
279 | 198k | Ok(()) |
280 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::remove_constant_phis::<&dyn cranelift_codegen::isa::TargetIsa> <cranelift_codegen::context::Context>::remove_constant_phis::<&dyn cranelift_codegen::isa::TargetIsa> Line | Count | Source | 273 | 198k | pub fn remove_constant_phis<'a, FOI: Into<FlagsOrIsa<'a>>>( | 274 | 198k | &mut self, | 275 | 198k | fisa: FOI, | 276 | 198k | ) -> CodegenResult<()> { | 277 | 198k | do_remove_constant_phis(&mut self.func, &mut self.domtree); | 278 | 198k | self.verify_if(fisa)?; | 279 | 198k | Ok(()) | 280 | 198k | } |
|
281 | | |
282 | | /// Perform NaN canonicalizing rewrites on the function. |
283 | 198k | pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { |
284 | | // Currently only RiscV64 is the only arch that may not have vector support. |
285 | 198k | let has_vector_support = match isa.triple().architecture { |
286 | 0 | Architecture::Riscv64(_) => match isa.isa_flags().iter().find(|f| f.name == "has_v") {Unexecuted instantiation: <cranelift_codegen::context::Context>::canonicalize_nans::{closure#0}Unexecuted instantiation: <cranelift_codegen::context::Context>::canonicalize_nans::{closure#0} |
287 | 0 | Some(value) => value.as_bool().unwrap_or(false), |
288 | 0 | None => false, |
289 | | }, |
290 | 198k | _ => true, |
291 | | }; |
292 | 198k | do_nan_canonicalization(&mut self.func, has_vector_support); |
293 | 198k | self.verify_if(isa) |
294 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::canonicalize_nans <cranelift_codegen::context::Context>::canonicalize_nans Line | Count | Source | 283 | 198k | pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { | 284 | | // Currently only RiscV64 is the only arch that may not have vector support. | 285 | 198k | let has_vector_support = match isa.triple().architecture { | 286 | 0 | Architecture::Riscv64(_) => match isa.isa_flags().iter().find(|f| f.name == "has_v") { | 287 | 0 | Some(value) => value.as_bool().unwrap_or(false), | 288 | 0 | None => false, | 289 | | }, | 290 | 198k | _ => true, | 291 | | }; | 292 | 198k | do_nan_canonicalization(&mut self.func, has_vector_support); | 293 | 198k | self.verify_if(isa) | 294 | 198k | } |
|
295 | | |
296 | | /// Run the legalizer for `isa` on the function. |
297 | 198k | pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { |
298 | | // Legalization invalidates the domtree and loop_analysis by mutating the CFG. |
299 | | // TODO: Avoid doing this when legalization doesn't actually mutate the CFG. |
300 | 198k | self.domtree.clear(); |
301 | 198k | self.loop_analysis.clear(); |
302 | 198k | self.cfg.clear(); |
303 | | |
304 | | // Run some specific legalizations only. |
305 | 198k | simple_legalize(&mut self.func, isa); |
306 | 198k | self.verify_if(isa) |
307 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::legalize <cranelift_codegen::context::Context>::legalize Line | Count | Source | 297 | 198k | pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { | 298 | | // Legalization invalidates the domtree and loop_analysis by mutating the CFG. | 299 | | // TODO: Avoid doing this when legalization doesn't actually mutate the CFG. | 300 | 198k | self.domtree.clear(); | 301 | 198k | self.loop_analysis.clear(); | 302 | 198k | self.cfg.clear(); | 303 | | | 304 | | // Run some specific legalizations only. | 305 | 198k | simple_legalize(&mut self.func, isa); | 306 | 198k | self.verify_if(isa) | 307 | 198k | } |
|
308 | | |
309 | | /// Compute the control flow graph. |
310 | 198k | pub fn compute_cfg(&mut self) { |
311 | 198k | self.cfg.compute(&self.func) |
312 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::compute_cfg <cranelift_codegen::context::Context>::compute_cfg Line | Count | Source | 310 | 198k | pub fn compute_cfg(&mut self) { | 311 | 198k | self.cfg.compute(&self.func) | 312 | 198k | } |
|
313 | | |
314 | | /// Compute dominator tree. |
315 | 198k | pub fn compute_domtree(&mut self) { |
316 | 198k | self.domtree.compute(&self.func, &self.cfg); |
317 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::compute_domtree <cranelift_codegen::context::Context>::compute_domtree Line | Count | Source | 315 | 198k | pub fn compute_domtree(&mut self) { | 316 | 198k | self.domtree.compute(&self.func, &self.cfg); | 317 | 198k | } |
|
318 | | |
319 | | /// Compute the loop analysis. |
320 | 198k | pub fn compute_loop_analysis(&mut self) { |
321 | 198k | self.loop_analysis |
322 | 198k | .compute(&self.func, &self.cfg, &self.domtree) |
323 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::compute_loop_analysis <cranelift_codegen::context::Context>::compute_loop_analysis Line | Count | Source | 320 | 198k | pub fn compute_loop_analysis(&mut self) { | 321 | 198k | self.loop_analysis | 322 | 198k | .compute(&self.func, &self.cfg, &self.domtree) | 323 | 198k | } |
|
324 | | |
325 | | /// Compute the control flow graph and dominator tree. |
326 | 0 | pub fn flowgraph(&mut self) { |
327 | 0 | self.compute_cfg(); |
328 | 0 | self.compute_domtree() |
329 | 0 | } Unexecuted instantiation: <cranelift_codegen::context::Context>::flowgraph Unexecuted instantiation: <cranelift_codegen::context::Context>::flowgraph |
330 | | |
331 | | /// Perform unreachable code elimination. |
332 | 198k | pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()> |
333 | 198k | where |
334 | 198k | FOI: Into<FlagsOrIsa<'a>>, |
335 | | { |
336 | 198k | eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree); |
337 | 198k | self.verify_if(fisa) |
338 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::eliminate_unreachable_code::<&dyn cranelift_codegen::isa::TargetIsa> <cranelift_codegen::context::Context>::eliminate_unreachable_code::<&dyn cranelift_codegen::isa::TargetIsa> Line | Count | Source | 332 | 198k | pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()> | 333 | 198k | where | 334 | 198k | FOI: Into<FlagsOrIsa<'a>>, | 335 | | { | 336 | 198k | eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree); | 337 | 198k | self.verify_if(fisa) | 338 | 198k | } |
|
339 | | |
340 | | /// Replace all redundant loads with the known values in |
341 | | /// memory. These are loads whose values were already loaded by |
342 | | /// other loads earlier, as well as loads whose values were stored |
343 | | /// by a store instruction to the same instruction (so-called |
344 | | /// "store-to-load forwarding"). |
345 | 0 | pub fn replace_redundant_loads(&mut self) -> CodegenResult<()> { |
346 | 0 | let mut analysis = AliasAnalysis::new(&self.func, &self.domtree); |
347 | 0 | analysis.compute_and_update_aliases(&mut self.func); |
348 | 0 | Ok(()) |
349 | 0 | } Unexecuted instantiation: <cranelift_codegen::context::Context>::replace_redundant_loads Unexecuted instantiation: <cranelift_codegen::context::Context>::replace_redundant_loads |
350 | | |
351 | | /// Harvest candidate left-hand sides for superoptimization with Souper. |
352 | | #[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 | | /// Run optimizations via the egraph infrastructure. |
362 | 198k | pub fn egraph_pass<'a, FOI>( |
363 | 198k | &mut self, |
364 | 198k | fisa: FOI, |
365 | 198k | ctrl_plane: &mut ControlPlane, |
366 | 198k | ) -> CodegenResult<()> |
367 | 198k | where |
368 | 198k | FOI: Into<FlagsOrIsa<'a>>, |
369 | | { |
370 | 198k | let _tt = timing::egraph(); |
371 | | |
372 | 198k | trace!( |
373 | | "About to optimize with egraph phase:\n{}", |
374 | 0 | self.func.display() |
375 | | ); |
376 | 198k | let fisa = fisa.into(); |
377 | 198k | self.compute_loop_analysis(); |
378 | 198k | let mut alias_analysis = AliasAnalysis::new(&self.func, &self.domtree); |
379 | 198k | let mut pass = EgraphPass::new( |
380 | 198k | &mut self.func, |
381 | 198k | &self.domtree, |
382 | 198k | &self.loop_analysis, |
383 | 198k | &mut alias_analysis, |
384 | 198k | &fisa.flags, |
385 | 198k | ctrl_plane, |
386 | | ); |
387 | 198k | pass.run(); |
388 | 198k | log::debug!("egraph stats: {:?}", pass.stats); |
389 | 198k | trace!("After egraph optimization:\n{}", self.func.display()); |
390 | | |
391 | 198k | self.verify_if(fisa) |
392 | 198k | } Unexecuted instantiation: <cranelift_codegen::context::Context>::egraph_pass::<&dyn cranelift_codegen::isa::TargetIsa> <cranelift_codegen::context::Context>::egraph_pass::<&dyn cranelift_codegen::isa::TargetIsa> Line | Count | Source | 362 | 198k | pub fn egraph_pass<'a, FOI>( | 363 | 198k | &mut self, | 364 | 198k | fisa: FOI, | 365 | 198k | ctrl_plane: &mut ControlPlane, | 366 | 198k | ) -> CodegenResult<()> | 367 | 198k | where | 368 | 198k | FOI: Into<FlagsOrIsa<'a>>, | 369 | | { | 370 | 198k | let _tt = timing::egraph(); | 371 | | | 372 | 198k | trace!( | 373 | | "About to optimize with egraph phase:\n{}", | 374 | 0 | self.func.display() | 375 | | ); | 376 | 198k | let fisa = fisa.into(); | 377 | 198k | self.compute_loop_analysis(); | 378 | 198k | let mut alias_analysis = AliasAnalysis::new(&self.func, &self.domtree); | 379 | 198k | let mut pass = EgraphPass::new( | 380 | 198k | &mut self.func, | 381 | 198k | &self.domtree, | 382 | 198k | &self.loop_analysis, | 383 | 198k | &mut alias_analysis, | 384 | 198k | &fisa.flags, | 385 | 198k | ctrl_plane, | 386 | | ); | 387 | 198k | pass.run(); | 388 | 198k | log::debug!("egraph stats: {:?}", pass.stats); | 389 | 198k | trace!("After egraph optimization:\n{}", self.func.display()); | 390 | | | 391 | 198k | self.verify_if(fisa) | 392 | 198k | } |
|
393 | | } |