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             // Note: single-pass is currently disabled
70             // (https://github.com/bytecodealliance/regalloc2/issues/217).
71         };
72 
73         regalloc2::run(&vcode, vcode.abi.machine_env(), &options)
74             .map_err(|err| {
75                 log::error!(
76                     "Register allocation error for vcode\n{:?}\nError: {:?}\nCLIF for error:\n{:?}",
77                     vcode,
78                     err,
79                     f,
80                 );
81                 err
82             })
83             .expect("register allocation")
84     };
85 
86     // Run the regalloc checker, if requested.
87     if b.flags().regalloc_checker() {
88         let _tt = timing::regalloc_checker();
89         let mut checker = regalloc2::checker::Checker::new(&vcode, vcode.abi.machine_env());
90         checker.prepare(&regalloc_result);
91         checker
92             .run()
93             .map_err(|err| {
94                 log::error!(
95                     "Register allocation checker errors:\n{:?}\nfor vcode:\n{:?}",
96                     err,
97                     vcode
98                 );
99                 err
100             })
101             .expect("register allocation checker");
102     }
103 
104     Ok((vcode, regalloc_result))
105 }
106