cranelift_codegen/ir/
globalvalue.rs

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