1 //! Global values.
2 
3 use crate::ir::immediates::{Imm64, Offset32};
4 use crate::ir::{ExternalName, GlobalValue, MemFlags, Type};
5 use crate::isa::TargetIsa;
6 use core::fmt;
7 
8 #[cfg(feature = "enable-serde")]
9 use 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))]
14 pub 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 
86 impl GlobalValueData {
87     /// Assume that `self` is an `GlobalValueData::Symbol` and return its name.
symbol_name(&self) -> &ExternalName88     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.
global_type(&self, isa: &dyn TargetIsa) -> Type96     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 
105 impl fmt::Display for GlobalValueData {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result106     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107         match *self {
108             Self::VMContext => write!(f, "vmctx"),
109             Self::Load {
110                 base,
111                 offset,
112                 global_type,
113                 flags,
114             } => write!(f, "load.{global_type}{flags} {base}{offset}"),
115             Self::IAddImm {
116                 global_type,
117                 base,
118                 offset,
119             } => write!(f, "iadd_imm.{global_type} {base}, {offset}"),
120             Self::Symbol {
121                 ref name,
122                 offset,
123                 colocated,
124                 tls,
125             } => {
126                 write!(
127                     f,
128                     "symbol {}{}{}",
129                     if colocated { "colocated " } else { "" },
130                     if tls { "tls " } else { "" },
131                     name.display(None)
132                 )?;
133                 let offset_val: i64 = offset.into();
134                 if offset_val > 0 {
135                     write!(f, "+")?;
136                 }
137                 if offset_val != 0 {
138                     write!(f, "{offset}")?;
139                 }
140                 Ok(())
141             }
142             Self::DynScaleTargetConst { vector_type } => {
143                 write!(f, "dyn_scale_target_const.{vector_type}")
144             }
145         }
146     }
147 }
148