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