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