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 = crate::machinst::Lower::new(f, abi, emit_info, block_order, sigs)?;
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 validation of proof-carrying-code facts, if requested.
51     if b.flags().enable_pcc() {
52         pcc::check_vcode_facts(f, &vcode, b).map_err(CodegenError::Pcc)?;
53     }
54 
55     // Perform register allocation.
56     let regalloc_result = {
57         let _tt = timing::regalloc();
58         let mut options = RegallocOptions::default();
59         options.verbose_log = b.flags().regalloc_verbose_logs();
60 
61         if cfg!(debug_assertions) {
62             options.validate_ssa = true;
63         }
64 
65         regalloc2::run(&vcode, vcode.machine_env(), &options)
66             .map_err(|err| {
67                 log::error!(
68                     "Register allocation error for vcode\n{:?}\nError: {:?}\nCLIF for error:\n{:?}",
69                     vcode,
70                     err,
71                     f,
72                 );
73                 err
74             })
75             .expect("register allocation")
76     };
77 
78     // Run the regalloc checker, if requested. Also run the checker if
79     // PCC is enabled (PCC only validates up to pre-regalloc VCode, so
80     // for a full guarantee we need to ensure that regalloc did a
81     // faithful translation to allocated machine code.)
82     if b.flags().regalloc_checker() || b.flags().enable_pcc() {
83         let _tt = timing::regalloc_checker();
84         let mut checker = regalloc2::checker::Checker::new(&vcode, vcode.machine_env());
85         checker.prepare(&regalloc_result);
86         checker
87             .run()
88             .map_err(|err| {
89                 log::error!(
90                     "Register allocation checker errors:\n{:?}\nfor vcode:\n{:?}",
91                     err,
92                     vcode
93                 );
94                 err
95             })
96             .expect("register allocation checker");
97     }
98 
99     Ok((vcode, regalloc_result))
100 }
101