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