/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 | } |