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