cranelift_codegen/ir/globalvalue.rs
1//! Global values.
2
3use crate::ir::immediates::{Imm64, Offset32};
4use crate::ir::{ExternalName, GlobalValue, MemFlags, MemFlagsSet, Type};
5use crate::isa::TargetIsa;
6use core::fmt;
7
8#[cfg(feature = "enable-serde")]
9use serde_derive::{Deserialize, Serialize};
10
11/// Information about a global value declaration.
12#[derive(Debug, Clone, PartialEq, Hash)]
13#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
14pub enum GlobalValueData {
15 /// Value is the address of the VM context struct.
16 VMContext,
17
18 /// Value is pointed to by another global value.
19 ///
20 /// The `base` global value is assumed to contain a pointer. This global value is computed
21 /// by loading from memory at that pointer value. The memory must be accessible, and
22 /// naturally aligned to hold a value of the type. The data at this address is assumed
23 /// to never change while the current function is executing.
24 Load {
25 /// The base pointer global value.
26 base: GlobalValue,
27
28 /// Offset added to the base pointer before doing the load.
29 offset: Offset32,
30
31 /// Type of the loaded value.
32 global_type: Type,
33
34 /// Specifies the memory flags to be used by the load. Guaranteed to be notrap and aligned.
35 flags: MemFlags,
36 },
37
38 /// Value is an offset from another global value.
39 IAddImm {
40 /// The base pointer global value.
41 base: GlobalValue,
42
43 /// Byte offset to be added to the value.
44 offset: Imm64,
45
46 /// Type of the iadd.
47 global_type: Type,
48 },
49
50 /// Value is symbolic, meaning it's a name which will be resolved to an
51 /// actual value later (eg. by linking). Cranelift itself does not interpret
52 /// this name; it's used by embedders to link with other data structures.
53 ///
54 /// For now, symbolic values always have pointer type, and represent
55 /// addresses, however in the future they could be used to represent other
56 /// things as well.
57 Symbol {
58 /// The symbolic name.
59 name: ExternalName,
60
61 /// Offset from the symbol. This can be used instead of IAddImm to represent folding an
62 /// offset into a symbol.
63 offset: Imm64,
64
65 /// Will this symbol be defined nearby, such that it will always be a certain distance
66 /// away, after linking? If so, references to it can avoid going through a GOT. Note that
67 /// symbols meant to be preemptible cannot be colocated.
68 ///
69 /// If `true`, some backends may use relocation forms that have limited range: for example,
70 /// a +/- 2^27-byte range on AArch64. See the documentation for
71 /// `RelocDistance` for more details.
72 colocated: bool,
73
74 /// Does this symbol refer to a thread local storage value?
75 tls: bool,
76 },
77
78 /// Value is a multiple of how many instances of `vector_type` will fit in
79 /// a target vector register.
80 DynScaleTargetConst {
81 /// Base vector type.
82 vector_type: Type,
83 },
84}
85
86impl GlobalValueData {
87 /// Assume that `self` is an `GlobalValueData::Symbol` and return its name.
88 pub fn symbol_name(&self) -> &ExternalName {
89 match *self {
90 Self::Symbol { ref name, .. } => name,
91 _ => panic!("only symbols have names"),
92 }
93 }
94
95 /// Return the type of this global.
96 pub fn global_type(&self, isa: &dyn TargetIsa) -> Type {
97 match *self {
98 Self::VMContext { .. } | Self::Symbol { .. } => isa.pointer_type(),
99 Self::IAddImm { global_type, .. } | Self::Load { global_type, .. } => global_type,
100 Self::DynScaleTargetConst { .. } => isa.pointer_type(),
101 }
102 }
103}
104
105impl GlobalValueData {
106 /// Return a display wrapper that can resolve `MemFlags` entities.
107 pub fn display<'a>(&'a self, mem_flags: &'a MemFlagsSet) -> DisplayGlobalValueData<'a> {
108 DisplayGlobalValueData {
109 data: self,
110 mem_flags,
111 }
112 }
113}
114
115/// Wrapper for displaying a `GlobalValueData` with resolved `MemFlags`.
116pub struct DisplayGlobalValueData<'a> {
117 data: &'a GlobalValueData,
118 mem_flags: &'a MemFlagsSet,
119}
120
121impl fmt::Display for DisplayGlobalValueData<'_> {
122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123 match *self.data {
124 GlobalValueData::VMContext => write!(f, "vmctx"),
125 GlobalValueData::Load {
126 base,
127 offset,
128 global_type,
129 flags,
130 } => {
131 let flags_data = self.mem_flags[flags];
132 write!(f, "load.{global_type}{flags_data} {base}{offset}")
133 }
134 GlobalValueData::IAddImm {
135 global_type,
136 base,
137 offset,
138 } => write!(f, "iadd_imm.{global_type} {base}, {offset}"),
139 GlobalValueData::Symbol {
140 ref name,
141 offset,
142 colocated,
143 tls,
144 } => {
145 write!(
146 f,
147 "symbol {}{}{}",
148 if colocated { "colocated " } else { "" },
149 if tls { "tls " } else { "" },
150 name.display(None)
151 )?;
152 let offset_val: i64 = offset.into();
153 if offset_val > 0 {
154 write!(f, "+")?;
155 }
156 if offset_val != 0 {
157 write!(f, "{offset}")?;
158 }
159 Ok(())
160 }
161 GlobalValueData::DynScaleTargetConst { vector_type } => {
162 write!(f, "dyn_scale_target_const.{vector_type}")
163 }
164 }
165 }
166}
167
168impl fmt::Display for GlobalValueData {
169 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
170 match *self {
171 Self::VMContext => write!(f, "vmctx"),
172 Self::Load {
173 base,
174 offset,
175 global_type,
176 flags,
177 } => write!(f, "load.{global_type} {flags} {base}{offset}"),
178 Self::IAddImm {
179 global_type,
180 base,
181 offset,
182 } => write!(f, "iadd_imm.{global_type} {base}, {offset}"),
183 Self::Symbol {
184 ref name,
185 offset,
186 colocated,
187 tls,
188 } => {
189 write!(
190 f,
191 "symbol {}{}{}",
192 if colocated { "colocated " } else { "" },
193 if tls { "tls " } else { "" },
194 name.display(None)
195 )?;
196 let offset_val: i64 = offset.into();
197 if offset_val > 0 {
198 write!(f, "+")?;
199 }
200 if offset_val != 0 {
201 write!(f, "{offset}")?;
202 }
203 Ok(())
204 }
205 Self::DynScaleTargetConst { vector_type } => {
206 write!(f, "dyn_scale_target_const.{vector_type}")
207 }
208 }
209 }
210}