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, FrameUnwindKind, FrameUnwindSink, 14 MemoryCodeSink, RelocSink, StackmapSink, 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::licm::do_licm; 23 use crate::loop_analysis::LoopAnalysis; 24 use crate::nan_canonicalization::do_nan_canonicalization; 25 use crate::postopt::do_postopt; 26 use crate::redundant_reload_remover::RedundantReloadRemover; 27 use crate::regalloc; 28 use crate::result::CodegenResult; 29 use crate::settings::{FlagsOrIsa, OptLevel}; 30 use crate::simple_gvn::do_simple_gvn; 31 use crate::simple_preopt::do_preopt; 32 use crate::timing; 33 use crate::unreachable_code::eliminate_unreachable_code; 34 use crate::value_label::{build_value_labels_ranges, ComparableSourceLoc, ValueLabelsRanges}; 35 use crate::verifier::{verify_context, verify_locations, VerifierErrors, VerifierResult}; 36 use alloc::vec::Vec; 37 use log::debug; 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 /// Register allocation context. 51 pub regalloc: regalloc::Context, 52 53 /// Loop analysis of `func`. 54 pub loop_analysis: LoopAnalysis, 55 56 /// Redundant-reload remover context. 57 pub redundant_reload_remover: RedundantReloadRemover, 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 regalloc: regalloc::Context::new(), 79 loop_analysis: LoopAnalysis::new(), 80 redundant_reload_remover: RedundantReloadRemover::new(), 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.regalloc.clear(); 90 self.loop_analysis.clear(); 91 self.redundant_reload_remover.clear(); 92 } 93 94 /// Compile the function, and emit machine code into a `Vec<u8>`. 95 /// 96 /// Run the function through all the passes necessary to generate code for the target ISA 97 /// represented by `isa`, as well as the final step of emitting machine code into a 98 /// `Vec<u8>`. The machine code is not relocated. Instead, any relocations are emitted 99 /// into `relocs`. 100 /// 101 /// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as 102 /// needed, so it provides a safe interface. 103 /// 104 /// Returns information about the function's code and read-only data. 105 pub fn compile_and_emit( 106 &mut self, 107 isa: &dyn TargetIsa, 108 mem: &mut Vec<u8>, 109 relocs: &mut dyn RelocSink, 110 traps: &mut dyn TrapSink, 111 stackmaps: &mut dyn StackmapSink, 112 ) -> CodegenResult<CodeInfo> { 113 let info = self.compile(isa)?; 114 let old_len = mem.len(); 115 mem.resize(old_len + info.total_size as usize, 0); 116 let new_info = unsafe { 117 self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps, stackmaps) 118 }; 119 debug_assert!(new_info == info); 120 Ok(info) 121 } 122 123 /// Compile the function. 124 /// 125 /// Run the function through all the passes necessary to generate code for the target ISA 126 /// represented by `isa`. This does not include the final step of emitting machine code into a 127 /// code sink. 128 /// 129 /// Returns information about the function's code and read-only data. 130 pub fn compile(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> { 131 let _tt = timing::compile(); 132 self.verify_if(isa)?; 133 debug!("Compiling:\n{}", self.func.display(isa)); 134 135 let opt_level = isa.flags().opt_level(); 136 137 self.compute_cfg(); 138 if opt_level != OptLevel::None { 139 self.preopt(isa)?; 140 } 141 if isa.flags().enable_nan_canonicalization() { 142 self.canonicalize_nans(isa)?; 143 } 144 self.legalize(isa)?; 145 if opt_level != OptLevel::None { 146 self.postopt(isa)?; 147 self.compute_domtree(); 148 self.compute_loop_analysis(); 149 self.licm(isa)?; 150 self.simple_gvn(isa)?; 151 } 152 self.compute_domtree(); 153 self.eliminate_unreachable_code(isa)?; 154 if opt_level != OptLevel::None { 155 self.dce(isa)?; 156 } 157 self.regalloc(isa)?; 158 self.prologue_epilogue(isa)?; 159 if opt_level == OptLevel::Speed || opt_level == OptLevel::SpeedAndSize { 160 self.redundant_reload_remover(isa)?; 161 } 162 if opt_level == OptLevel::SpeedAndSize { 163 self.shrink_instructions(isa)?; 164 } 165 let result = self.relax_branches(isa); 166 167 debug!("Compiled:\n{}", self.func.display(isa)); 168 result 169 } 170 171 /// Emit machine code directly into raw memory. 172 /// 173 /// Write all of the function's machine code to the memory at `mem`. The size of the machine 174 /// code is returned by `compile` above. 175 /// 176 /// The machine code is not relocated. Instead, any relocations are emitted into `relocs`. 177 /// 178 /// # Safety 179 /// 180 /// This function is unsafe since it does not perform bounds checking on the memory buffer, 181 /// and it can't guarantee that the `mem` pointer is valid. 182 /// 183 /// Returns information about the emitted code and data. 184 pub unsafe fn emit_to_memory( 185 &self, 186 isa: &dyn TargetIsa, 187 mem: *mut u8, 188 relocs: &mut dyn RelocSink, 189 traps: &mut dyn TrapSink, 190 stackmaps: &mut dyn StackmapSink, 191 ) -> CodeInfo { 192 let _tt = timing::binemit(); 193 let mut sink = MemoryCodeSink::new(mem, relocs, traps, stackmaps); 194 isa.emit_function_to_memory(&self.func, &mut sink); 195 sink.info 196 } 197 198 /// Emit unwind information. 199 /// 200 /// Requires that the function layout be calculated (see `relax_branches`). 201 /// 202 /// Only some calling conventions (e.g. Windows fastcall) will have unwind information. 203 /// This is a no-op if the function has no unwind information. 204 pub fn emit_unwind_info( 205 &self, 206 isa: &dyn TargetIsa, 207 kind: FrameUnwindKind, 208 sink: &mut dyn FrameUnwindSink, 209 ) { 210 isa.emit_unwind_info(&self.func, kind, sink); 211 } 212 213 /// Run the verifier on the function. 214 /// 215 /// Also check that the dominator tree and control flow graph are consistent with the function. 216 pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> { 217 let mut errors = VerifierErrors::default(); 218 let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors); 219 220 if errors.is_empty() { 221 Ok(()) 222 } else { 223 Err(errors) 224 } 225 } 226 227 /// Run the verifier only if the `enable_verifier` setting is true. 228 pub fn verify_if<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> CodegenResult<()> { 229 let fisa = fisa.into(); 230 if fisa.flags.enable_verifier() { 231 self.verify(fisa)?; 232 } 233 Ok(()) 234 } 235 236 /// Run the locations verifier on the function. 237 pub fn verify_locations(&self, isa: &dyn TargetIsa) -> VerifierResult<()> { 238 let mut errors = VerifierErrors::default(); 239 let _ = verify_locations(isa, &self.func, &self.cfg, None, &mut errors); 240 241 if errors.is_empty() { 242 Ok(()) 243 } else { 244 Err(errors) 245 } 246 } 247 248 /// Run the locations verifier only if the `enable_verifier` setting is true. 249 pub fn verify_locations_if(&self, isa: &dyn TargetIsa) -> CodegenResult<()> { 250 if isa.flags().enable_verifier() { 251 self.verify_locations(isa)?; 252 } 253 Ok(()) 254 } 255 256 /// Perform dead-code elimination on the function. 257 pub fn dce<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> { 258 do_dce(&mut self.func, &mut self.domtree); 259 self.verify_if(fisa)?; 260 Ok(()) 261 } 262 263 /// Perform pre-legalization rewrites on the function. 264 pub fn preopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 265 do_preopt(&mut self.func, &mut self.cfg, isa); 266 self.verify_if(isa)?; 267 Ok(()) 268 } 269 270 /// Perform NaN canonicalizing rewrites on the function. 271 pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 272 do_nan_canonicalization(&mut self.func); 273 self.verify_if(isa) 274 } 275 276 /// Run the legalizer for `isa` on the function. 277 pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 278 // Legalization invalidates the domtree and loop_analysis by mutating the CFG. 279 // TODO: Avoid doing this when legalization doesn't actually mutate the CFG. 280 self.domtree.clear(); 281 self.loop_analysis.clear(); 282 legalize_function(&mut self.func, &mut self.cfg, isa); 283 debug!("Legalized:\n{}", self.func.display(isa)); 284 self.verify_if(isa) 285 } 286 287 /// Perform post-legalization rewrites on the function. 288 pub fn postopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 289 do_postopt(&mut self.func, isa); 290 self.verify_if(isa)?; 291 Ok(()) 292 } 293 294 /// Compute the control flow graph. 295 pub fn compute_cfg(&mut self) { 296 self.cfg.compute(&self.func) 297 } 298 299 /// Compute dominator tree. 300 pub fn compute_domtree(&mut self) { 301 self.domtree.compute(&self.func, &self.cfg) 302 } 303 304 /// Compute the loop analysis. 305 pub fn compute_loop_analysis(&mut self) { 306 self.loop_analysis 307 .compute(&self.func, &self.cfg, &self.domtree) 308 } 309 310 /// Compute the control flow graph and dominator tree. 311 pub fn flowgraph(&mut self) { 312 self.compute_cfg(); 313 self.compute_domtree() 314 } 315 316 /// Perform simple GVN on the function. 317 pub fn simple_gvn<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> { 318 do_simple_gvn(&mut self.func, &mut self.domtree); 319 self.verify_if(fisa) 320 } 321 322 /// Perform LICM on the function. 323 pub fn licm(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 324 do_licm( 325 isa, 326 &mut self.func, 327 &mut self.cfg, 328 &mut self.domtree, 329 &mut self.loop_analysis, 330 ); 331 self.verify_if(isa) 332 } 333 334 /// Perform unreachable code elimination. 335 pub fn eliminate_unreachable_code<'a, FOI>(&mut self, fisa: FOI) -> CodegenResult<()> 336 where 337 FOI: Into<FlagsOrIsa<'a>>, 338 { 339 eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree); 340 self.verify_if(fisa) 341 } 342 343 /// Run the register allocator. 344 pub fn regalloc(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 345 self.regalloc 346 .run(isa, &mut self.func, &mut self.cfg, &mut self.domtree) 347 } 348 349 /// Insert prologue and epilogues after computing the stack frame layout. 350 pub fn prologue_epilogue(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 351 isa.prologue_epilogue(&mut self.func)?; 352 self.verify_if(isa)?; 353 self.verify_locations_if(isa)?; 354 Ok(()) 355 } 356 357 /// Do redundant-reload removal after allocation of both registers and stack slots. 358 pub fn redundant_reload_remover(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 359 self.redundant_reload_remover 360 .run(isa, &mut self.func, &self.cfg); 361 self.verify_if(isa)?; 362 Ok(()) 363 } 364 365 /// Run the instruction shrinking pass. 366 pub fn shrink_instructions(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> { 367 shrink_instructions(&mut self.func, isa); 368 self.verify_if(isa)?; 369 self.verify_locations_if(isa)?; 370 Ok(()) 371 } 372 373 /// Run the branch relaxation pass and return information about the function's code and 374 /// read-only data. 375 pub fn relax_branches(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> { 376 let info = relax_branches(&mut self.func, &mut self.cfg, &mut self.domtree, isa)?; 377 self.verify_if(isa)?; 378 self.verify_locations_if(isa)?; 379 Ok(info) 380 } 381 382 /// Builds ranges and location for specified value labels. 383 pub fn build_value_labels_ranges( 384 &self, 385 isa: &dyn TargetIsa, 386 ) -> CodegenResult<ValueLabelsRanges> { 387 Ok(build_value_labels_ranges::<ComparableSourceLoc>( 388 &self.func, 389 &self.regalloc, 390 isa, 391 )) 392 } 393 } 394