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