Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/cranelift-codegen-0.91.1/src/legalizer/globalvalue.rs
Line
Count
Source (jump to first uncovered line)
1
//! Legalization of global values.
2
//!
3
//! This module exports the `expand_global_value` function which transforms a `global_value`
4
//! instruction into code that depends on the kind of global value referenced.
5
6
use crate::cursor::{Cursor, FuncCursor};
7
use crate::ir::{self, InstBuilder};
8
use crate::isa::TargetIsa;
9
10
/// Expand a `global_value` instruction according to the definition of the global value.
11
108k
pub fn expand_global_value(
12
108k
    inst: ir::Inst,
13
108k
    func: &mut ir::Function,
14
108k
    isa: &dyn TargetIsa,
15
108k
    global_value: ir::GlobalValue,
16
108k
) {
17
108k
    crate::trace!(
18
0
        "expanding global value: {:?}: {}",
19
0
        inst,
20
0
        func.dfg.display_inst(inst)
21
    );
22
23
108k
    match func.global_values[global_value] {
24
26.4k
        ir::GlobalValueData::VMContext => vmctx_addr(inst, func),
25
        ir::GlobalValueData::IAddImm {
26
0
            base,
27
0
            offset,
28
0
            global_type,
29
0
        } => iadd_imm_addr(inst, func, base, offset.into(), global_type),
30
        ir::GlobalValueData::Load {
31
81.7k
            base,
32
81.7k
            offset,
33
81.7k
            global_type,
34
81.7k
            readonly,
35
81.7k
        } => load_addr(inst, func, base, offset, global_type, readonly, isa),
36
0
        ir::GlobalValueData::Symbol { tls, .. } => symbol(inst, func, global_value, isa, tls),
37
0
        ir::GlobalValueData::DynScaleTargetConst { vector_type } => {
38
0
            const_vector_scale(inst, func, vector_type, isa)
39
        }
40
    }
41
108k
}
42
43
0
fn const_vector_scale(inst: ir::Inst, func: &mut ir::Function, ty: ir::Type, isa: &dyn TargetIsa) {
44
0
    assert!(ty.bytes() <= 16);
45
46
    // Use a minimum of 128-bits for the base type.
47
0
    let base_bytes = std::cmp::max(ty.bytes(), 16);
48
0
    let scale = (isa.dynamic_vector_bytes(ty) / base_bytes) as i64;
49
0
    assert!(scale > 0);
50
0
    let pos = FuncCursor::new(func).at_inst(inst);
51
0
    pos.func.dfg.replace(inst).iconst(isa.pointer_type(), scale);
52
0
}
53
54
/// Expand a `global_value` instruction for a vmctx global.
55
26.4k
fn vmctx_addr(inst: ir::Inst, func: &mut ir::Function) {
56
26.4k
    // Get the value representing the `vmctx` argument.
57
26.4k
    let vmctx = func
58
26.4k
        .special_param(ir::ArgumentPurpose::VMContext)
59
26.4k
        .expect("Missing vmctx parameter");
60
26.4k
61
26.4k
    // Replace the `global_value` instruction's value with an alias to the vmctx arg.
62
26.4k
    let result = func.dfg.first_result(inst);
63
26.4k
    func.dfg.clear_results(inst);
64
26.4k
    func.dfg.change_to_alias(result, vmctx);
65
26.4k
    func.layout.remove_inst(inst);
66
26.4k
}
67
68
/// Expand a `global_value` instruction for an iadd_imm global.
69
0
fn iadd_imm_addr(
70
0
    inst: ir::Inst,
71
0
    func: &mut ir::Function,
72
0
    base: ir::GlobalValue,
73
0
    offset: i64,
74
0
    global_type: ir::Type,
75
0
) {
76
0
    let mut pos = FuncCursor::new(func).at_inst(inst);
77
78
    // Get the value for the lhs. For tidiness, expand VMContext here so that we avoid
79
    // `vmctx_addr` which creates an otherwise unneeded value alias.
80
0
    let lhs = if let ir::GlobalValueData::VMContext = pos.func.global_values[base] {
81
0
        pos.func
82
0
            .special_param(ir::ArgumentPurpose::VMContext)
83
0
            .expect("Missing vmctx parameter")
84
    } else {
85
0
        pos.ins().global_value(global_type, base)
86
    };
87
88
    // Simply replace the `global_value` instruction with an `iadd_imm`, reusing the result value.
89
0
    pos.func.dfg.replace(inst).iadd_imm(lhs, offset);
90
0
}
91
92
/// Expand a `global_value` instruction for a load global.
93
81.7k
fn load_addr(
94
81.7k
    inst: ir::Inst,
95
81.7k
    func: &mut ir::Function,
96
81.7k
    base: ir::GlobalValue,
97
81.7k
    offset: ir::immediates::Offset32,
98
81.7k
    global_type: ir::Type,
99
81.7k
    readonly: bool,
100
81.7k
    isa: &dyn TargetIsa,
101
81.7k
) {
102
81.7k
    // We need to load a pointer from the `base` global value, so insert a new `global_value`
103
81.7k
    // instruction. This depends on the iterative legalization loop. Note that the IR verifier
104
81.7k
    // detects any cycles in the `load` globals.
105
81.7k
    let ptr_ty = isa.pointer_type();
106
81.7k
    let mut pos = FuncCursor::new(func).at_inst(inst);
107
81.7k
    pos.use_srcloc(inst);
108
109
    // Get the value for the base. For tidiness, expand VMContext here so that we avoid
110
    // `vmctx_addr` which creates an otherwise unneeded value alias.
111
81.7k
    let base_addr = if let ir::GlobalValueData::VMContext = pos.func.global_values[base] {
112
81.7k
        pos.func
113
81.7k
            .special_param(ir::ArgumentPurpose::VMContext)
114
81.7k
            .expect("Missing vmctx parameter")
115
    } else {
116
0
        pos.ins().global_value(ptr_ty, base)
117
    };
118
119
    // Global-value loads are always notrap and aligned. They may be readonly.
120
81.7k
    let mut mflags = ir::MemFlags::trusted();
121
81.7k
    if readonly {
122
69.9k
        mflags.set_readonly();
123
69.9k
    }
124
125
    // Perform the load.
126
81.7k
    pos.func
127
81.7k
        .dfg
128
81.7k
        .replace(inst)
129
81.7k
        .load(global_type, mflags, base_addr, offset);
130
81.7k
}
131
132
/// Expand a `global_value` instruction for a symbolic name global.
133
0
fn symbol(
134
0
    inst: ir::Inst,
135
0
    func: &mut ir::Function,
136
0
    gv: ir::GlobalValue,
137
0
    isa: &dyn TargetIsa,
138
0
    tls: bool,
139
0
) {
140
0
    let ptr_ty = isa.pointer_type();
141
0
142
0
    if tls {
143
0
        func.dfg.replace(inst).tls_value(ptr_ty, gv);
144
0
    } else {
145
0
        func.dfg.replace(inst).symbol_value(ptr_ty, gv);
146
0
    }
147
0
}