Skip to main content

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}