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