1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//! Various utilities to load MIR.
//! Allow to easily load the MIR code generated by a specific pass.
use rustc_hir::def_id::DefId;
use rustc_middle::mir::Body;
use rustc_middle::ty::TyCtxt;

use crate::translate::translate_ctx::MirLevel;

/// Indicates if the constants should be extracted in their own identifier,
/// or if they must be evaluated to a constant value, depending on the
/// MIR level which we extract.
pub fn extract_constants_at_top_level(level: MirLevel) -> bool {
    match level {
        MirLevel::Built => true,
        MirLevel::Promoted => true,
        MirLevel::Optimized => false,
    }
}

/// Are boxe manipulations desugared to very low-level code using raw pointers,
/// unique and non-null pointers? See [crate::types::TyKind::RawPtr] for detailed explanations.
pub fn boxes_are_desugared(level: MirLevel) -> bool {
    match level {
        MirLevel::Built => false,
        MirLevel::Promoted => false,
        MirLevel::Optimized => true,
    }
}

/// Query the MIR for a function at a specific level. Return `None` in the case of a foreign body
/// with no MIR available (e.g. because it is not available for inlining).
pub fn get_mir_for_def_id_and_level(
    tcx: TyCtxt<'_>,
    def_id: DefId,
    level: MirLevel,
) -> Option<Body<'_>> {
    // Below: we **clone** the bodies to make sure we don't have issues with
    // locked values (we had in the past).
    if let Some(local_def_id) = def_id.as_local() {
        match level {
            MirLevel::Built => {
                let body = tcx.mir_built(local_def_id);
                if !body.is_stolen() {
                    return Some(body.borrow().clone());
                }
            }
            MirLevel::Promoted => {
                let (body, _) = tcx.mir_promoted(local_def_id);
                if !body.is_stolen() {
                    return Some(body.borrow().clone());
                }
            }
            MirLevel::Optimized => {}
        }
        // We fall back to optimized MIR if the requested body was stolen.
    }

    // There are only two MIRs we can fetch for non-local bodies: CTFE mir for globals and
    // const fns, and optimized MIR for inlinable functions. The rest don't have MIR in the
    // rlib.
    let body = if tcx.is_mir_available(def_id) {
        if let Some(local_def_id) = def_id.as_local()
            && !matches!(
                tcx.hir().body_const_context(local_def_id),
                None | Some(rustc_hir::ConstContext::ConstFn)
            )
        {
            tcx.mir_for_ctfe(def_id).clone()
        } else {
            tcx.optimized_mir(def_id).clone()
        }
    } else if tcx.is_ctfe_mir_available(def_id) {
        tcx.mir_for_ctfe(def_id).clone()
    } else {
        return None;
    };
    Some(body)
}