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::binemit::{ 13 relax_branches, shrink_instructions, CodeInfo, MemoryCodeSink, RelocSink, StackMapSink, 14 TrapSink, 15 }; 16 use crate::dce::do_dce; 17 use crate::dominator_tree::DominatorTree; 18 use crate::flowgraph::ControlFlowGraph; 19 use crate::ir::Function; 20 use crate::isa::TargetIsa; 21 use crate::legalize_function; 22 use crate::legalizer::simple_legalize; 23 use crate::licm::do_licm; 24 use crate::loop_analysis::LoopAnalysis; 25 use crate::machinst::{MachCompileResult, MachStackMap}; 26 use crate::nan_canonicalization::do_nan_canonicalization; 27 use crate::postopt::do_postopt; 28 use crate::redundant_reload_remover::RedundantReloadRemover; 29 use crate::regalloc; 30 use crate::remove_constant_phis::do_remove_constant_phis; 31 use crate::result::CodegenResult; 32 use crate::settings::{FlagsOrIsa, OptLevel}; 33 use crate::simple_gvn::do_simple_gvn; 34 use crate::simple_preopt::do_preopt; 35 use crate::timing; 36 use crate::unreachable_code::eliminate_unreachable_code; 37 use crate::value_label::{build_value_labels_ranges, ComparableSourceLoc, ValueLabelsRanges}; 38 use crate::verifier::{verify_context, verify_locations, VerifierErrors, VerifierResult}; 39 #[cfg(feature = "souper-harvest")] 40 use alloc::string::String; 41 use alloc::vec::Vec; 42 use log::debug; 43 44 #[cfg(feature = "souper-harvest")] 45 use crate::souper_harvest::do_souper_harvest; 46 47 /// Persistent data structures and compilation pipeline. 48 pub struct Context { 49 /// The function we're compiling. 50 pub func: Function, 51 52 /// The control flow graph of `func`. 53 pub cfg: ControlFlowGraph, 54 55 /// Dominator tree for `func`. 56 pub domtree: DominatorTree, 57 58 /// Register allocation context. 59 pub regalloc: regalloc::Context, 60 61 /// Loop analysis of `func`. 62 pub loop_analysis: LoopAnalysis, 63 64 /// Redundant-reload remover context. 65 pub redundant_reload_remover: RedundantReloadRemover, 66 67 /// Result of MachBackend compilation, if computed. 68 pub mach_compile_result: Option<MachCompileResult>, 69 70 /// Flag: do we want a disassembly with the MachCompileResult? 71 pub want_disasm: bool, 72 } 73 74 impl Context { 75 /// Allocate a new compilation context. 76 /// 77 /// The returned instance should be reused for compiling multiple functions in order to avoid 78 /// needless allocator thrashing. 79 pub fn new() -> Self { 80 Self::for_function(Function::new()) 81 } 82 83 /// Allocate a new compilation context with an existing Function. 84 /// 85 /// The returned instance should be reused for compiling multiple functions in order to avoid 86 /// needless allocator thrashing. 87 pub fn for_function(func: Function) -> Self { 88 Self { 89 func, 90 cfg: ControlFlowGraph::new(), 91 domtree: DominatorTree::new(), 92 regalloc: regalloc::Context::new(), 93 loop_analysis: LoopAnalysis::new(), 94 redundant_reload_remover: RedundantReloadRemover::new(), 95 mach_compile_result: None, 96 want_disasm: false, 97 } 98 } 99 100 /// Clear all data structures in this context. 101 pub fn clear(&mut self) { 102 self.func.clear(); 103 self.cfg.clear(); 104 self.domtree.clear(); 105 self.regalloc.clear(); 106 self.loop_analysis.clear(); 107 self.redundant_reload_remover.clear(); 108 self.mach_compile_result = None; 109 self.want_disasm = false; 110 } 111 112 /// Set the flag to request a disassembly when compiling with a 113 /// `MachBackend` backend. 114 pub fn set_disasm(&mut self, val: bool) { 115 self.want_disasm = val; 116 } 117 118 /// Compile the function, and emit machine code into a `Vec<u8>`. 119 /// 120 /// Run the function through all the passes necessary to generate code for the target ISA 121 /// represented by `isa`, as well as the final step of emitting machine code into a 122 /// `Vec<u8>`. The machine code is not relocated. Instead, any relocations are emitted 123 /// into `relocs`. 124 /// 125 /// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as 126 /// needed, so it provides a safe interface. 127 /// 128 /// Returns information about the function's code and read-only data. 129 pub fn compile_and_emit( 130 &mut self, 131 isa: &dyn TargetIsa, 132 mem: &mut Vec<u8>, 133 relocs: &mut dyn RelocSink, 134 traps: &mut dyn TrapSink, 135 stack_maps: &mut dyn StackMapSink, 136 ) -> CodegenResult<CodeInfo> { 137 let info = self.compile(isa)?; 138 let old_len = mem.len(); 139 mem.resize(old_len + info.total_size as usize, 0); 140 let new_info = unsafe { 141 self.emit_to_memory( 142 isa, 143 mem.as_mut_ptr().add(old_len), 144 relocs, 145 traps, 146 stack_maps, 147 ) 148 }; 149 debug_assert!(new_info == info); 150 Ok(info) 151 } 152 153 /// Compile the function. 154 /// 155 /// Run the function through all the passes necessary to generate code for the target ISA 156 /// represented by `isa`. This does not include the final step of emitting machine code into a 157 /// code sink. 158 /// 159 /// Returns information about the function's code and read-only data. 160 pub fn compile(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> { 161 let _tt = timing::compile(); 162 self.verify_if(isa)?; 163 164 let opt_level = isa.flags().opt_level(); 165 debug!( 166 "Compiling (opt level {:?}):\n{}", 167 opt_level, 168 self.func.display(isa) 169 ); 170 171 self.compute_cfg(); 172 if opt_level != OptLevel::None { 173 self.preopt(isa)?; 174 } 175 if isa.flags().enable_nan_canonicalization() { 176 self.canonicalize_nans(isa)?; 177 } 178 179 self.legalize(isa)?; 180 if opt_level != OptLevel::None { 181 self.postopt(isa)?; 182 self.compute_domtree(); 183 self.compute_loop_analysis(); 184 self.licm(isa)?; 185 self.simple_gvn(isa)?; 186 } 187 188 self.compute_domtree(); 189 self.eliminate_unreachable_code(isa)?; 190 if opt_level != OptLevel::None { 191 self.dce(isa)?; 192 } 193 194 self.remove_constant_phis(isa)?; 195 196 if let Some(backend) = isa.get_mach_backend() { 197 let result = backend.compile_function(&self.func, self.want_disasm)?; 198 let info = result.code_info(); 199 self.mach_compile_result = Some(result); 200 Ok(info) 201 } else { 202 self.regalloc(isa)?; 203 self.prologue_epilogue(isa)?; 204 if opt_level == OptLevel::Speed || opt_level == OptLevel::SpeedAndSize { 205 self.redundant_reload_remover(isa)?; 206 } 207 if opt_level == OptLevel::SpeedAndSize { 208 self.shrink_instructions(isa)?; 209 } 210 let result = self.relax_branches(isa); 211 212 debug!("Compiled:\n{}", self.func.display(isa)); 213 result 214 } 215 } 216 217 /// Emit machine code directly into raw memory. 218 /// 219 /// Write all of the function's machine code to the memory at `mem`. The size of the machine 220 /// code is returned by `compile` above. 221 /// 222 /// The machine code is not relocated. Instead, any relocations are emitted into `relocs`. 223 /// 224 /// # Safety 225 /// 226 /// This function is unsafe since it does not perform bounds checking on the memory buffer, 227 /// and it can't guarantee that the `mem` pointer is valid. 228 /// 229 /// Returns information about the emitted code and data. 230 pub unsafe fn emit_to_memory( 231 &self, 232 isa: &dyn TargetIsa, 233 mem: *mut u8, 234 relocs: &mut dyn RelocSink, 235 traps: &mut dyn TrapSink, 236 stack_maps: &mut dyn StackMapSink, 237 ) -> CodeInfo { 238 let _tt = timing::binemit(); 239 let mut sink = MemoryCodeSink::new(mem, relocs, traps, stack_maps); 240 if let Some(ref result) = &self.mach_compile_result { 241 result.buffer.emit(&mut sink); 242 let info = sink.info; 243 // New backends do not emit StackMaps through the `CodeSink` because its interface 244 // requires `Value`s; instead, the `StackMap` objects are directly accessible via 245 // `result.buffer.stack_maps()`. 246 for &MachStackMap { 247 offset_end, 248 ref stack_map, 249 .. 250 } in result.buffer.stack_maps() 251 { 252 stack_maps.add_stack_map(offset_end, stack_map.clone()); 253 } 254 info 255 } else { 256 isa.emit_function_to_memory(&self.func, &mut sink); 257 sink.info 258 } 259 } 260 261 /// Creates unwind information for the function. 262 /// 263 /// Returns `None` if the function has no unwind information. 264 #[cfg(feature = "unwind")] 265 pub fn create_unwind_info( 266 &self, 267 isa: &dyn TargetIsa, 268 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> { 269 if let Some(backend) = isa.get_mach_backend() { 270 use crate::isa::CallConv; 271 use crate::machinst::UnwindInfoKind; 272 let unwind_info_kind = match self.func.signature.call_conv { 273 CallConv::Fast | CallConv::Cold | CallConv::SystemV => UnwindInfoKind::SystemV, 274 CallConv::WindowsFastcall => UnwindInfoKind::Windows, 275 _ => UnwindInfoKind::None, 276 }; 277 let result = self.mach_compile_result.as_ref().unwrap(); 278 return backend.emit_unwind_info(result, unwind_info_kind); 279 } 280 isa.create_unwind_info(&self.func) 281 } 282 283 /// Run the verifier on the function. 284 /// 285 /// Also check that the dominator tree and control flow graph are consistent with the function. 286 pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> { 287 let mut errors = VerifierErrors::default(); 288 let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors); 289 290 if errors.is_empty() { 291 Ok(()) 292 } else { 293 Err(errors) 294 } 295 } 296 297 /// Run the verifier only if the `enable_verifier` setting is true. 298 pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> { 299 let fisa = fisa.into(); 300 if fisa.flags.enable_verifier() { 301 self.verify(fisa)?; 302 } 303 Ok(()) 304 } 305 306 /// Run the locations verifier on the function. 307 pub fn verify_locations(&self, isa: &dyn TargetIsa) -> VerifierResult<()> { 308 let mut errors = VerifierErrors::default(); 309 let _ = verify_locations(isa, &self.func, &self.cfg, None, &mut errors); 310 311 if errors.is_empty() { 312 Ok(()) 313 } else { 314 Err(errors) 315 } 316 } 317 318 /// Run the locations verifier only if the `enable_verifier` setting is true. 319 pub fn verify_locations_if(&self, isa: &dyn TargetIsa) -> CodegenResult<()> { 320 if isa.flags().enable_verifier() { 321 self.verify_locations(isa)?; 322 } 323 Ok(()) 324 } 325 326 /// Perform dead-code elimination on the function. 327 pub fn dce<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> { 328 do_dce(&mut self.func, &mut self.domtree); 329 self.verify_if(fisa)?; 330 Ok(()) 331 } 332 333 /// Perform constant-phi removal on the function. 334 pub fn remove_constant_phis<'a, FOI: Into<FlagsOrIsa<'a>>>( 335 &mut self, 336 fisa: FOI, 337 ) -> CodegenResult<()> { 338 do_remove_constant_phis(&mut self.func, &mut self.domtree); 339 self.verify_if(fisa)?; 340 Ok(()) 341 } 342 343 /// Perform pre-legalization rewrites on the function. 344 pub fn preopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 345 do_preopt(&mut self.func, &mut self.cfg, isa); 346 self.verify_if(isa)?; 347 Ok(()) 348 } 349 350 /// Perform NaN canonicalizing rewrites on the function. 351 pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 352 do_nan_canonicalization(&mut self.func); 353 self.verify_if(isa) 354 } 355 356 /// Run the legalizer for `isa` on the function. 357 pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 358 // Legalization invalidates the domtree and loop_analysis by mutating the CFG. 359 // TODO: Avoid doing this when legalization doesn't actually mutate the CFG. 360 self.domtree.clear(); 361 self.loop_analysis.clear(); 362 if isa.get_mach_backend().is_some() { 363 // Run some specific legalizations only. 364 simple_legalize(&mut self.func, &mut self.cfg, isa); 365 self.verify_if(isa) 366 } else { 367 legalize_function(&mut self.func, &mut self.cfg, isa); 368 debug!("Legalized:\n{}", self.func.display(isa)); 369 self.verify_if(isa) 370 } 371 } 372 373 /// Perform post-legalization rewrites on the function. 374 pub fn postopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 375 do_postopt(&mut self.func, isa); 376 self.verify_if(isa)?; 377 Ok(()) 378 } 379 380 /// Compute the control flow graph. 381 pub fn compute_cfg(&mut self) { 382 self.cfg.compute(&self.func) 383 } 384 385 /// Compute dominator tree. 386 pub fn compute_domtree(&mut self) { 387 self.domtree.compute(&self.func, &self.cfg) 388 } 389 390 /// Compute the loop analysis. 391 pub fn compute_loop_analysis(&mut self) { 392 self.loop_analysis 393 .compute(&self.func, &self.cfg, &self.domtree) 394 } 395 396 /// Compute the control flow graph and dominator tree. 397 pub fn flowgraph(&mut self) { 398 self.compute_cfg(); 399 self.compute_domtree() 400 } 401 402 /// Perform simple GVN on the function. 403 pub fn simple_gvn<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> { 404 do_simple_gvn(&mut self.func, &mut self.domtree); 405 self.verify_if(fisa) 406 } 407 408 /// Perform LICM on the function. 409 pub fn licm(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 410 do_licm( 411 isa, 412 &mut self.func, 413 &mut self.cfg, 414 &mut self.domtree, 415 &mut self.loop_analysis, 416 ); 417 self.verify_if(isa) 418 } 419 420 /// Perform unreachable code elimination. 421 pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()> 422 where 423 FOI: Into<FlagsOrIsa<'a>>, 424 { 425 eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree); 426 self.verify_if(fisa) 427 } 428 429 /// Run the register allocator. 430 pub fn regalloc(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 431 self.regalloc 432 .run(isa, &mut self.func, &mut self.cfg, &mut self.domtree) 433 } 434 435 /// Insert prologue and epilogues after computing the stack frame layout. 436 pub fn prologue_epilogue(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 437 isa.prologue_epilogue(&mut self.func)?; 438 self.verify_if(isa)?; 439 self.verify_locations_if(isa)?; 440 Ok(()) 441 } 442 443 /// Do redundant-reload removal after allocation of both registers and stack slots. 444 pub fn redundant_reload_remover(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 445 self.redundant_reload_remover 446 .run(isa, &mut self.func, &self.cfg); 447 self.verify_if(isa)?; 448 Ok(()) 449 } 450 451 /// Run the instruction shrinking pass. 452 pub fn shrink_instructions(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 453 shrink_instructions(&mut self.func, isa); 454 self.verify_if(isa)?; 455 self.verify_locations_if(isa)?; 456 Ok(()) 457 } 458 459 /// Run the branch relaxation pass and return information about the function's code and 460 /// read-only data. 461 pub fn relax_branches(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> { 462 let info = relax_branches(&mut self.func, &mut self.cfg, &mut self.domtree, isa)?; 463 self.verify_if(isa)?; 464 self.verify_locations_if(isa)?; 465 Ok(info) 466 } 467 468 /// Builds ranges and location for specified value labels. 469 pub fn build_value_labels_ranges( 470 &self, 471 isa: &dyn TargetIsa, 472 ) -> CodegenResult<ValueLabelsRanges> { 473 Ok(build_value_labels_ranges::<ComparableSourceLoc>( 474 &self.func, 475 &self.regalloc, 476 self.mach_compile_result.as_ref(), 477 isa, 478 )) 479 } 480 481 /// Harvest candidate left-hand sides for superoptimization with Souper. 482 #[cfg(feature = "souper-harvest")] 483 pub fn souper_harvest( 484 &mut self, 485 out: &mut std::sync::mpsc::Sender<String>, 486 ) -> CodegenResult<()> { 487 do_souper_harvest(&self.func, out); 488 Ok(()) 489 } 490 } 491