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