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