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::binemit::CodeInfo; 14 use crate::dce::do_dce; 15 use crate::dominator_tree::DominatorTree; 16 use crate::flowgraph::ControlFlowGraph; 17 use crate::ir::Function; 18 use crate::isa::TargetIsa; 19 use crate::legalizer::simple_legalize; 20 use crate::licm::do_licm; 21 use crate::loop_analysis::LoopAnalysis; 22 use crate::machinst::MachCompileResult; 23 use crate::nan_canonicalization::do_nan_canonicalization; 24 use crate::remove_constant_phis::do_remove_constant_phis; 25 use crate::result::CodegenResult; 26 use crate::settings::{FlagsOrIsa, OptLevel}; 27 use crate::simple_gvn::do_simple_gvn; 28 use crate::simple_preopt::do_preopt; 29 use crate::timing; 30 use crate::unreachable_code::eliminate_unreachable_code; 31 use crate::verifier::{verify_context, VerifierErrors, VerifierResult}; 32 #[cfg(feature = "souper-harvest")] 33 use alloc::string::String; 34 use alloc::vec::Vec; 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 mach_compile_result: Option<MachCompileResult>, 55 56 /// Flag: do we want a disassembly with the MachCompileResult? 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 pub fn new() -> Self { 66 Self::for_function(Function::new()) 67 } 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 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 mach_compile_result: None, 80 want_disasm: false, 81 } 82 } 83 84 /// Clear all data structures in this context. 85 pub fn clear(&mut self) { 86 self.func.clear(); 87 self.cfg.clear(); 88 self.domtree.clear(); 89 self.loop_analysis.clear(); 90 self.mach_compile_result = None; 91 self.want_disasm = false; 92 } 93 94 /// Set the flag to request a disassembly when compiling with a 95 /// `MachBackend` backend. 96 pub fn set_disasm(&mut self, val: bool) { 97 self.want_disasm = val; 98 } 99 100 /// Compile the function, and emit machine code into a `Vec<u8>`. 101 /// 102 /// Run the function through all the passes necessary to generate code for the target ISA 103 /// represented by `isa`, as well as the final step of emitting machine code into a 104 /// `Vec<u8>`. The machine code is not relocated. Instead, any relocations can be obtained 105 /// from `mach_compile_result`. 106 /// 107 /// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as 108 /// needed, so it provides a safe interface. 109 /// 110 /// Returns information about the function's code and read-only data. 111 pub fn compile_and_emit( 112 &mut self, 113 isa: &dyn TargetIsa, 114 mem: &mut Vec<u8>, 115 ) -> CodegenResult<()> { 116 let info = self.compile(isa)?; 117 let old_len = mem.len(); 118 mem.resize(old_len + info.total_size as usize, 0); 119 let new_info = unsafe { self.emit_to_memory(mem.as_mut_ptr().add(old_len)) }; 120 debug_assert!(new_info == info); 121 Ok(()) 122 } 123 124 /// Compile the function. 125 /// 126 /// Run the function through all the passes necessary to generate code for the target ISA 127 /// represented by `isa`. This does not include the final step of emitting machine code into a 128 /// code sink. 129 /// 130 /// Returns information about the function's code and read-only data. 131 pub fn compile(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> { 132 let _tt = timing::compile(); 133 self.verify_if(isa)?; 134 135 let opt_level = isa.flags().opt_level(); 136 log::debug!( 137 "Compiling (opt level {:?}):\n{}", 138 opt_level, 139 self.func.display() 140 ); 141 142 self.compute_cfg(); 143 if opt_level != OptLevel::None { 144 self.preopt(isa)?; 145 } 146 if isa.flags().enable_nan_canonicalization() { 147 self.canonicalize_nans(isa)?; 148 } 149 150 self.legalize(isa)?; 151 if opt_level != OptLevel::None { 152 self.compute_domtree(); 153 self.compute_loop_analysis(); 154 self.licm(isa)?; 155 self.simple_gvn(isa)?; 156 } 157 158 self.compute_domtree(); 159 self.eliminate_unreachable_code(isa)?; 160 if opt_level != OptLevel::None { 161 self.dce(isa)?; 162 } 163 164 self.remove_constant_phis(isa)?; 165 166 if opt_level != OptLevel::None { 167 self.replace_redundant_loads()?; 168 self.simple_gvn(isa)?; 169 } 170 171 let result = isa.compile_function(&self.func, self.want_disasm)?; 172 let info = result.code_info(); 173 self.mach_compile_result = Some(result); 174 Ok(info) 175 } 176 177 /// Emit machine code directly into raw memory. 178 /// 179 /// Write all of the function's machine code to the memory at `mem`. The size of the machine 180 /// code is returned by `compile` above. 181 /// 182 /// The machine code is not relocated. 183 /// Instead, any relocations can be obtained from `mach_compile_result`. 184 /// 185 /// # Safety 186 /// 187 /// This function is unsafe since it does not perform bounds checking on the memory buffer, 188 /// and it can't guarantee that the `mem` pointer is valid. 189 /// 190 /// Returns information about the emitted code and data. 191 #[deny(unsafe_op_in_unsafe_fn)] 192 pub unsafe fn emit_to_memory(&self, mem: *mut u8) -> CodeInfo { 193 let _tt = timing::binemit(); 194 let result = self 195 .mach_compile_result 196 .as_ref() 197 .expect("only using mach backend now"); 198 let info = result.code_info(); 199 200 let mem = unsafe { std::slice::from_raw_parts_mut(mem, info.total_size as usize) }; 201 mem.copy_from_slice(result.buffer.data()); 202 203 info 204 } 205 206 /// If available, return information about the code layout in the 207 /// final machine code: the offsets (in bytes) of each basic-block 208 /// start, and all basic-block edges. 209 pub fn get_code_bb_layout(&self) -> Option<(Vec<usize>, Vec<(usize, usize)>)> { 210 if let Some(result) = self.mach_compile_result.as_ref() { 211 Some(( 212 result.bb_starts.iter().map(|&off| off as usize).collect(), 213 result 214 .bb_edges 215 .iter() 216 .map(|&(from, to)| (from as usize, to as usize)) 217 .collect(), 218 )) 219 } else { 220 None 221 } 222 } 223 224 /// Creates unwind information for the function. 225 /// 226 /// Returns `None` if the function has no unwind information. 227 #[cfg(feature = "unwind")] 228 pub fn create_unwind_info( 229 &self, 230 isa: &dyn TargetIsa, 231 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> { 232 let unwind_info_kind = isa.unwind_info_kind(); 233 let result = self.mach_compile_result.as_ref().unwrap(); 234 isa.emit_unwind_info(result, unwind_info_kind) 235 } 236 237 /// Run the verifier on the function. 238 /// 239 /// Also check that the dominator tree and control flow graph are consistent with the function. 240 pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> { 241 let mut errors = VerifierErrors::default(); 242 let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors); 243 244 if errors.is_empty() { 245 Ok(()) 246 } else { 247 Err(errors) 248 } 249 } 250 251 /// Run the verifier only if the `enable_verifier` setting is true. 252 pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> { 253 let fisa = fisa.into(); 254 if fisa.flags.enable_verifier() { 255 self.verify(fisa)?; 256 } 257 Ok(()) 258 } 259 260 /// Perform dead-code elimination on the function. 261 pub fn dce<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> { 262 do_dce(&mut self.func, &mut self.domtree); 263 self.verify_if(fisa)?; 264 Ok(()) 265 } 266 267 /// Perform constant-phi removal on the function. 268 pub fn remove_constant_phis<'a, FOI: Into<FlagsOrIsa<'a>>>( 269 &mut self, 270 fisa: FOI, 271 ) -> CodegenResult<()> { 272 do_remove_constant_phis(&mut self.func, &mut self.domtree); 273 self.verify_if(fisa)?; 274 Ok(()) 275 } 276 277 /// Perform pre-legalization rewrites on the function. 278 pub fn preopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 279 do_preopt(&mut self.func, &mut self.cfg, isa); 280 self.verify_if(isa)?; 281 Ok(()) 282 } 283 284 /// Perform NaN canonicalizing rewrites on the function. 285 pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 286 do_nan_canonicalization(&mut self.func); 287 self.verify_if(isa) 288 } 289 290 /// Run the legalizer for `isa` on the function. 291 pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 292 // Legalization invalidates the domtree and loop_analysis by mutating the CFG. 293 // TODO: Avoid doing this when legalization doesn't actually mutate the CFG. 294 self.domtree.clear(); 295 self.loop_analysis.clear(); 296 297 // Run some specific legalizations only. 298 simple_legalize(&mut self.func, &mut self.cfg, isa); 299 self.verify_if(isa) 300 } 301 302 /// Compute the control flow graph. 303 pub fn compute_cfg(&mut self) { 304 self.cfg.compute(&self.func) 305 } 306 307 /// Compute dominator tree. 308 pub fn compute_domtree(&mut self) { 309 self.domtree.compute(&self.func, &self.cfg) 310 } 311 312 /// Compute the loop analysis. 313 pub fn compute_loop_analysis(&mut self) { 314 self.loop_analysis 315 .compute(&self.func, &self.cfg, &self.domtree) 316 } 317 318 /// Compute the control flow graph and dominator tree. 319 pub fn flowgraph(&mut self) { 320 self.compute_cfg(); 321 self.compute_domtree() 322 } 323 324 /// Perform simple GVN on the function. 325 pub fn simple_gvn<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> { 326 do_simple_gvn(&mut self.func, &mut self.domtree); 327 self.verify_if(fisa) 328 } 329 330 /// Perform LICM on the function. 331 pub fn licm(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 332 do_licm( 333 &mut self.func, 334 &mut self.cfg, 335 &mut self.domtree, 336 &mut self.loop_analysis, 337 ); 338 self.verify_if(isa) 339 } 340 341 /// Perform unreachable code elimination. 342 pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()> 343 where 344 FOI: Into<FlagsOrIsa<'a>>, 345 { 346 eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree); 347 self.verify_if(fisa) 348 } 349 350 /// Replace all redundant loads with the known values in 351 /// memory. These are loads whose values were already loaded by 352 /// other loads earlier, as well as loads whose values were stored 353 /// by a store instruction to the same instruction (so-called 354 /// "store-to-load forwarding"). 355 pub fn replace_redundant_loads(&mut self) -> CodegenResult<()> { 356 let mut analysis = AliasAnalysis::new(&mut self.func, &self.domtree); 357 analysis.compute_and_update_aliases(); 358 Ok(()) 359 } 360 361 /// Harvest candidate left-hand sides for superoptimization with Souper. 362 #[cfg(feature = "souper-harvest")] 363 pub fn souper_harvest( 364 &mut self, 365 out: &mut std::sync::mpsc::Sender<String>, 366 ) -> CodegenResult<()> { 367 do_souper_harvest(&self.func, out); 368 Ok(()) 369 } 370 } 371