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