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