cranelift_codegen/machinst/
compile.rs

1//! Compilation backend pipeline: optimized IR to VCode / binemit.
2
3use crate::dominator_tree::DominatorTree;
4use crate::ir::pcc;
5use crate::ir::Function;
6use crate::isa::TargetIsa;
7use crate::machinst::*;
8use crate::settings::RegallocAlgorithm;
9use crate::timing;
10use crate::trace;
11use crate::CodegenError;
12
13use regalloc2::{Algorithm, RegallocOptions};
14
15/// Compile the given function down to VCode with allocated registers, ready
16/// for binary emission.
17pub 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.machine_env(), &options)
73            .map_err(|err| {
74                log::error!(
75                    "Register allocation error for vcode\n{:?}\nError: {:?}\nCLIF for error:\n{:?}",
76                    vcode,
77                    err,
78                    f,
79                );
80                err
81            })
82            .expect("register allocation")
83    };
84
85    // Run the regalloc checker, if requested.
86    if b.flags().regalloc_checker() {
87        let _tt = timing::regalloc_checker();
88        let mut checker = regalloc2::checker::Checker::new(&vcode, vcode.machine_env());
89        checker.prepare(&regalloc_result);
90        checker
91            .run()
92            .map_err(|err| {
93                log::error!(
94                    "Register allocation checker errors:\n{:?}\nfor vcode:\n{:?}",
95                    err,
96                    vcode
97                );
98                err
99            })
100            .expect("register allocation checker");
101    }
102
103    Ok((vcode, regalloc_result))
104}