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