1 //! Global values.
2 
3 use crate::ir::immediates::{Imm64, Offset32};
4 use crate::ir::{ExternalName, GlobalValue, Type};
5 use crate::isa::TargetIsa;
6 use crate::machinst::RelocDistance;
7 use core::fmt;
8 
9 #[cfg(feature = "enable-serde")]
10 use serde::{Deserialize, Serialize};
11 
12 /// Information about a global value declaration.
13 #[derive(Clone)]
14 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
15 pub 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`](crate::machinst::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 
88 impl 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 
121 impl 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
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 }
171