1 //! Compilation backend pipeline: optimized IR to VCode / binemit.
2 
3 use crate::dominator_tree::DominatorTree;
4 use crate::ir::Function;
5 use crate::isa::TargetIsa;
6 use crate::machinst::*;
7 use crate::settings::RegallocAlgorithm;
8 use crate::timing;
9 use crate::trace;
10 
11 use regalloc2::{Algorithm, RegallocOptions};
12 
13 /// Compile the given function down to VCode with allocated registers, ready
14 /// for binary emission.
compile<B: LowerBackend + TargetIsa>( f: &Function, domtree: &DominatorTree, b: &B, abi: Callee<<<B as LowerBackend>::MInst as MachInst>::ABIMachineSpec>, emit_info: <B::MInst as MachInstEmit>::Info, sigs: SigSet, ctrl_plane: &mut ControlPlane, ) -> CodegenResult<(VCode<B::MInst>, regalloc2::Output)>15 pub fn compile<B: LowerBackend + TargetIsa>(
16     f: &Function,
17     domtree: &DominatorTree,
18     b: &B,
19     abi: Callee<<<B as LowerBackend>::MInst as MachInst>::ABIMachineSpec>,
20     emit_info: <B::MInst as MachInstEmit>::Info,
21     sigs: SigSet,
22     ctrl_plane: &mut ControlPlane,
23 ) -> CodegenResult<(VCode<B::MInst>, regalloc2::Output)> {
24     // Compute lowered block order.
25     let block_order = BlockLoweringOrder::new(f, domtree, ctrl_plane);
26 
27     // Build the lowering context.
28     let lower =
29         crate::machinst::Lower::new(f, abi, emit_info, block_order, sigs, b.flags().clone())?;
30 
31     // Lower the IR.
32     let vcode = {
33         log::debug!(
34             "Number of CLIF instructions to lower: {}",
35             f.dfg.num_insts()
36         );
37         log::debug!("Number of CLIF blocks to lower: {}", f.dfg.num_blocks());
38 
39         let _tt = timing::vcode_lower();
40         lower.lower(b, ctrl_plane)?
41     };
42 
43     log::debug!(
44         "Number of lowered vcode instructions: {}",
45         vcode.num_insts()
46     );
47     log::debug!("Number of lowered vcode blocks: {}", vcode.num_blocks());
48     trace!("vcode from lowering: \n{:?}", vcode);
49 
50     // Perform register allocation.
51     let regalloc_result = {
52         let _tt = timing::regalloc();
53         let mut options = RegallocOptions::default();
54         options.verbose_log = b.flags().regalloc_verbose_logs();
55 
56         if cfg!(debug_assertions) {
57             options.validate_ssa = true;
58         }
59 
60         options.algorithm = match b.flags().regalloc_algorithm() {
61             RegallocAlgorithm::Backtracking => Algorithm::Ion,
62             RegallocAlgorithm::SinglePass => Algorithm::Fastalloc,
63         };
64 
65         regalloc2::run(&vcode, vcode.abi.machine_env(), &options)
66             .map_err(|err| {
67                 log::error!(
68                     "Register allocation error for vcode\n{vcode:?}\nError: {err:?}\nCLIF for error:\n{f:?}",
69                 );
70                 err
71             })
72             .expect("register allocation")
73     };
74 
75     // Run the regalloc checker, if requested.
76     if b.flags().regalloc_checker() {
77         let _tt = timing::regalloc_checker();
78         let mut checker = regalloc2::checker::Checker::new(&vcode, &vcode.abi.machine_env());
79         checker.prepare(&regalloc_result);
80         checker
81             .run()
82             .map_err(|err| {
83                 log::error!("Register allocation checker errors:\n{err:?}\nfor vcode:\n{vcode:?}");
84                 err
85             })
86             .expect("register allocation checker");
87     }
88 
89     Ok((vcode, regalloc_result))
90 }
91