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}