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 
81 impl GlobalValueData {
82     /// Assume that `self` is an `GlobalValueData::Symbol` and return its name.
83     pub fn symbol_name(&self) -> &ExternalName {
84         match *self {
85             Self::Symbol { ref name, .. } => name,
86             _ => panic!("only symbols have names"),
87         }
88     }
89 
90     /// Return the type of this global.
91     pub fn global_type(&self, isa: &dyn TargetIsa) -> Type {
92         match *self {
93             Self::VMContext { .. } | Self::Symbol { .. } => isa.pointer_type(),
94             Self::IAddImm { global_type, .. } | Self::Load { global_type, .. } => global_type,
95         }
96     }
97 
98     /// If this global references a symbol, return an estimate of the relocation distance,
99     /// based on the `colocated` flag.
100     pub fn maybe_reloc_distance(&self) -> Option<RelocDistance> {
101         match self {
102             &GlobalValueData::Symbol {
103                 colocated: true, ..
104             } => Some(RelocDistance::Near),
105             &GlobalValueData::Symbol {
106                 colocated: false, ..
107             } => Some(RelocDistance::Far),
108             _ => None,
109         }
110     }
111 }
112 
113 impl fmt::Display for GlobalValueData {
114     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115         match *self {
116             Self::VMContext => write!(f, "vmctx"),
117             Self::Load {
118                 base,
119                 offset,
120                 global_type,
121                 readonly,
122             } => write!(
123                 f,
124                 "load.{} notrap aligned {}{}{}",
125                 global_type,
126                 if readonly { "readonly " } else { "" },
127                 base,
128                 offset
129             ),
130             Self::IAddImm {
131                 global_type,
132                 base,
133                 offset,
134             } => write!(f, "iadd_imm.{} {}, {}", global_type, base, offset),
135             Self::Symbol {
136                 ref name,
137                 offset,
138                 colocated,
139                 tls,
140             } => {
141                 write!(
142                     f,
143                     "symbol {}{}{}",
144                     if colocated { "colocated " } else { "" },
145                     if tls { "tls " } else { "" },
146                     name
147                 )?;
148                 let offset_val: i64 = offset.into();
149                 if offset_val > 0 {
150                     write!(f, "+")?;
151                 }
152                 if offset_val != 0 {
153                     write!(f, "{}", offset)?;
154                 }
155                 Ok(())
156             }
157         }
158     }
159 }
160