Skip to main content

cranelift_codegen/legalizer/
globalvalue.rs

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
6use crate::cursor::{Cursor, FuncCursor};
7use crate::flowgraph::ControlFlowGraph;
8use crate::ir::{self, InstBuilder};
9use crate::isa::TargetIsa;
10
11/// Expand a `global_value` instruction according to the definition of the global value.
12pub fn expand_global_value(
13    inst: ir::Inst,
14    func: &mut ir::Function,
15    _cfg: &mut ControlFlowGraph,
16    isa: &dyn TargetIsa,
17) {
18    // Unpack the instruction.
19    let gv = match func.dfg[inst] {
20        ir::InstructionData::UnaryGlobalValue {
21            opcode,
22            global_value,
23        } => {
24            debug_assert_eq!(opcode, ir::Opcode::GlobalValue);
25            global_value
26        }
27        _ => panic!("Wanted global_value: {}", func.dfg.display_inst(inst, None)),
28    };
29
30    match func.global_values[gv] {
31        ir::GlobalValueData::VMContext => vmctx_addr(inst, func),
32        ir::GlobalValueData::IAddImm {
33            base,
34            offset,
35            global_type,
36        } => iadd_imm_addr(inst, func, base, offset.into(), global_type),
37        ir::GlobalValueData::Load {
38            base,
39            offset,
40            global_type,
41            readonly,
42        } => load_addr(inst, func, base, offset, global_type, readonly, isa),
43        ir::GlobalValueData::Symbol { .. } => symbol(inst, func, gv, isa),
44    }
45}
46
47/// Expand a `global_value` instruction for a vmctx global.
48fn vmctx_addr(inst: ir::Inst, func: &mut ir::Function) {
49    // Get the value representing the `vmctx` argument.
50    let vmctx = func
51        .special_param(ir::ArgumentPurpose::VMContext)
52        .expect("Missing vmctx parameter");
53
54    // Replace the `global_value` instruction's value with an alias to the vmctx arg.
55    let result = func.dfg.first_result(inst);
56    func.dfg.clear_results(inst);
57    func.dfg.change_to_alias(result, vmctx);
58    func.layout.remove_inst(inst);
59}
60
61/// Expand a `global_value` instruction for an iadd_imm global.
62fn iadd_imm_addr(
63    inst: ir::Inst,
64    func: &mut ir::Function,
65    base: ir::GlobalValue,
66    offset: i64,
67    global_type: ir::Type,
68) {
69    let mut pos = FuncCursor::new(func).at_inst(inst);
70
71    // Get the value for the lhs. For tidiness, expand VMContext here so that we avoid
72    // `vmctx_addr` which creates an otherwise unneeded value alias.
73    let lhs = if let ir::GlobalValueData::VMContext = pos.func.global_values[base] {
74        pos.func
75            .special_param(ir::ArgumentPurpose::VMContext)
76            .expect("Missing vmctx parameter")
77    } else {
78        pos.ins().global_value(global_type, base)
79    };
80
81    // Simply replace the `global_value` instruction with an `iadd_imm`, reusing the result value.
82    pos.func.dfg.replace(inst).iadd_imm(lhs, offset);
83}
84
85/// Expand a `global_value` instruction for a load global.
86fn load_addr(
87    inst: ir::Inst,
88    func: &mut ir::Function,
89    base: ir::GlobalValue,
90    offset: ir::immediates::Offset32,
91    global_type: ir::Type,
92    readonly: bool,
93    isa: &dyn TargetIsa,
94) {
95    // We need to load a pointer from the `base` global value, so insert a new `global_value`
96    // instruction. This depends on the iterative legalization loop. Note that the IR verifier
97    // detects any cycles in the `load` globals.
98    let ptr_ty = isa.pointer_type();
99    let mut pos = FuncCursor::new(func).at_inst(inst);
100    pos.use_srcloc(inst);
101
102    // Get the value for the base. For tidiness, expand VMContext here so that we avoid
103    // `vmctx_addr` which creates an otherwise unneeded value alias.
104    let base_addr = if let ir::GlobalValueData::VMContext = pos.func.global_values[base] {
105        pos.func
106            .special_param(ir::ArgumentPurpose::VMContext)
107            .expect("Missing vmctx parameter")
108    } else {
109        pos.ins().global_value(ptr_ty, base)
110    };
111
112    // Global-value loads are always notrap and aligned. They may be readonly.
113    let mut mflags = ir::MemFlags::trusted();
114    if readonly {
115        mflags.set_readonly();
116    }
117
118    // Perform the load.
119    pos.func
120        .dfg
121        .replace(inst)
122        .load(global_type, mflags, base_addr, offset);
123}
124
125/// Expand a `global_value` instruction for a symbolic name global.
126fn symbol(inst: ir::Inst, func: &mut ir::Function, gv: ir::GlobalValue, isa: &dyn TargetIsa) {
127    let ptr_ty = isa.pointer_type();
128    func.dfg.replace(inst).symbol_value(ptr_ty, gv);
129}