1 //! External names. 2 //! 3 //! These are identifiers for declaring entities defined outside the current 4 //! function. The name of an external declaration doesn't have any meaning to 5 //! Cranelift, which compiles functions independently. 6 7 use crate::ir::{KnownSymbol, LibCall}; 8 use alloc::boxed::Box; 9 use core::fmt::{self, Write}; 10 use core::str::FromStr; 11 12 use cranelift_entity::EntityRef as _; 13 #[cfg(feature = "enable-serde")] 14 use serde::{Deserialize, Serialize}; 15 16 use super::entities::UserExternalNameRef; 17 use super::function::FunctionParameters; 18 19 /// An explicit name for a user-defined function, be it defined in code or in CLIF text. 20 /// 21 /// This is used both for naming a function (for debugging purposes) and for declaring external 22 /// functions. In the latter case, this becomes an `ExternalName`, which gets embedded in 23 /// relocations later, etc. 24 #[derive(Clone, Debug, PartialEq, Eq, Hash)] 25 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 26 pub enum UserFuncName { 27 /// A user-defined name, with semantics left to the user. 28 User(UserExternalName), 29 /// A name for a test case, mostly intended for Cranelift testing. 30 Testcase(TestcaseName), 31 } 32 33 impl UserFuncName { 34 /// Creates a new external name from a sequence of bytes. Caller is expected 35 /// to guarantee bytes are only ascii alphanumeric or `_`. 36 pub fn testcase<T: AsRef<[u8]>>(v: T) -> Self { 37 Self::Testcase(TestcaseName::new(v)) 38 } 39 40 /// Create a new external name from a user-defined external function reference. 41 pub fn user(namespace: u32, index: u32) -> Self { 42 Self::User(UserExternalName::new(namespace, index)) 43 } 44 } 45 46 impl Default for UserFuncName { 47 fn default() -> Self { 48 UserFuncName::User(UserExternalName::default()) 49 } 50 } 51 52 impl fmt::Display for UserFuncName { 53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 54 match self { 55 UserFuncName::User(user) => user.fmt(f), 56 UserFuncName::Testcase(testcase) => testcase.fmt(f), 57 } 58 } 59 } 60 61 /// An external name in a user-defined symbol table. 62 /// 63 /// Cranelift does not interpret these numbers in any way, so they can represent arbitrary values. 64 #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] 65 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 66 pub struct UserExternalName { 67 /// Arbitrary. 68 pub namespace: u32, 69 /// Arbitrary. 70 pub index: u32, 71 } 72 73 impl UserExternalName { 74 /// Creates a new [UserExternalName]. 75 pub fn new(namespace: u32, index: u32) -> Self { 76 Self { namespace, index } 77 } 78 } 79 80 impl fmt::Display for UserExternalName { 81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 82 write!(f, "u{}:{}", self.namespace, self.index) 83 } 84 } 85 86 /// A name for a test case. 87 #[derive(Clone, PartialEq, Eq, Hash)] 88 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 89 pub struct TestcaseName(Box<[u8]>); 90 91 impl fmt::Display for TestcaseName { 92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 93 f.write_char('%')?; 94 f.write_str(std::str::from_utf8(&self.0).unwrap()) 95 } 96 } 97 98 impl fmt::Debug for TestcaseName { 99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 100 write!(f, "{}", self) 101 } 102 } 103 104 impl TestcaseName { 105 pub(crate) fn new<T: AsRef<[u8]>>(v: T) -> Self { 106 Self(v.as_ref().into()) 107 } 108 } 109 110 /// The name of an external is either a reference to a user-defined symbol 111 /// table, or a short sequence of ascii bytes so that test cases do not have 112 /// to keep track of a symbol table. 113 /// 114 /// External names are primarily used as keys by code using Cranelift to map 115 /// from a `cranelift_codegen::ir::FuncRef` or similar to additional associated 116 /// data. 117 /// 118 /// External names can also serve as a primitive testing and debugging tool. 119 /// In particular, many `.clif` test files use function names to identify 120 /// functions. 121 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 122 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 123 pub enum ExternalName { 124 /// A reference to a name in a user-defined symbol table. 125 User(UserExternalNameRef), 126 /// A test case function name of up to a hardcoded amount of ascii 127 /// characters. This is not intended to be used outside test cases. 128 TestCase(TestcaseName), 129 /// A well-known runtime library function. 130 LibCall(LibCall), 131 /// A well-known symbol. 132 KnownSymbol(KnownSymbol), 133 } 134 135 impl Default for ExternalName { 136 fn default() -> Self { 137 Self::User(UserExternalNameRef::new(0)) 138 } 139 } 140 141 impl ExternalName { 142 /// Creates a new external name from a sequence of bytes. Caller is expected 143 /// to guarantee bytes are only ascii alphanumeric or `_`. 144 /// 145 /// # Examples 146 /// 147 /// ```rust 148 /// # use cranelift_codegen::ir::ExternalName; 149 /// // Create `ExternalName` from a string. 150 /// let name = ExternalName::testcase("hello"); 151 /// assert_eq!(name.display(None).to_string(), "%hello"); 152 /// ``` 153 pub fn testcase<T: AsRef<[u8]>>(v: T) -> Self { 154 Self::TestCase(TestcaseName::new(v)) 155 } 156 157 /// Create a new external name from a user-defined external function reference. 158 /// 159 /// # Examples 160 /// ```rust 161 /// # use cranelift_codegen::ir::{ExternalName, UserExternalNameRef}; 162 /// let user_func_ref: UserExternalNameRef = Default::default(); // usually obtained with `Function::declare_imported_user_function()` 163 /// let name = ExternalName::user(user_func_ref); 164 /// assert_eq!(name.display(None).to_string(), "userextname0"); 165 /// ``` 166 pub fn user(func_ref: UserExternalNameRef) -> Self { 167 Self::User(func_ref) 168 } 169 170 /// Returns a display for the current `ExternalName`, with extra context to prettify the 171 /// output. 172 pub fn display<'a>( 173 &'a self, 174 params: Option<&'a FunctionParameters>, 175 ) -> DisplayableExternalName<'a> { 176 DisplayableExternalName { name: self, params } 177 } 178 } 179 180 /// An `ExternalName` that has enough context to be displayed. 181 pub struct DisplayableExternalName<'a> { 182 name: &'a ExternalName, 183 params: Option<&'a FunctionParameters>, 184 } 185 186 impl<'a> fmt::Display for DisplayableExternalName<'a> { 187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 188 match &self.name { 189 ExternalName::User(func_ref) => { 190 if let Some(params) = self.params { 191 let name = ¶ms.user_named_funcs()[*func_ref]; 192 write!(f, "u{}:{}", name.namespace, name.index) 193 } else { 194 // Best effort. 195 write!(f, "{}", *func_ref) 196 } 197 } 198 ExternalName::TestCase(testcase) => testcase.fmt(f), 199 ExternalName::LibCall(lc) => write!(f, "%{}", lc), 200 ExternalName::KnownSymbol(ks) => write!(f, "%{}", ks), 201 } 202 } 203 } 204 205 impl FromStr for ExternalName { 206 type Err = (); 207 208 fn from_str(s: &str) -> Result<Self, Self::Err> { 209 // Try to parse as a known symbol 210 if let Ok(ks) = s.parse() { 211 return Ok(Self::KnownSymbol(ks)); 212 } 213 214 // Try to parse as a libcall name 215 if let Ok(lc) = s.parse() { 216 return Ok(Self::LibCall(lc)); 217 } 218 219 // Otherwise its a test case name 220 Ok(Self::testcase(s.as_bytes())) 221 } 222 } 223 224 #[cfg(test)] 225 mod tests { 226 use super::ExternalName; 227 use crate::ir::{ 228 entities::UserExternalNameRef, function::FunctionParameters, LibCall, UserExternalName, 229 }; 230 use alloc::string::ToString; 231 use core::u32; 232 use cranelift_entity::EntityRef as _; 233 234 #[cfg(target_pointer_width = "64")] 235 #[test] 236 fn externalname_size() { 237 assert_eq!(core::mem::size_of::<ExternalName>(), 24); 238 } 239 240 #[test] 241 fn display_testcase() { 242 assert_eq!(ExternalName::testcase("").display(None).to_string(), "%"); 243 assert_eq!(ExternalName::testcase("x").display(None).to_string(), "%x"); 244 assert_eq!( 245 ExternalName::testcase("x_1").display(None).to_string(), 246 "%x_1" 247 ); 248 assert_eq!( 249 ExternalName::testcase("longname12345678") 250 .display(None) 251 .to_string(), 252 "%longname12345678" 253 ); 254 assert_eq!( 255 ExternalName::testcase("longname123456789") 256 .display(None) 257 .to_string(), 258 "%longname123456789" 259 ); 260 } 261 262 #[test] 263 fn display_user() { 264 assert_eq!( 265 ExternalName::user(UserExternalNameRef::new(0)) 266 .display(None) 267 .to_string(), 268 "userextname0" 269 ); 270 assert_eq!( 271 ExternalName::user(UserExternalNameRef::new(1)) 272 .display(None) 273 .to_string(), 274 "userextname1" 275 ); 276 assert_eq!( 277 ExternalName::user(UserExternalNameRef::new((u32::MAX - 1) as _)) 278 .display(None) 279 .to_string(), 280 "userextname4294967294" 281 ); 282 283 let mut func_params = FunctionParameters::new(); 284 285 // ref 0 286 func_params.ensure_user_func_name(UserExternalName { 287 namespace: 13, 288 index: 37, 289 }); 290 291 // ref 1 292 func_params.ensure_user_func_name(UserExternalName { 293 namespace: 2, 294 index: 4, 295 }); 296 297 assert_eq!( 298 ExternalName::user(UserExternalNameRef::new(0)) 299 .display(Some(&func_params)) 300 .to_string(), 301 "u13:37" 302 ); 303 304 assert_eq!( 305 ExternalName::user(UserExternalNameRef::new(1)) 306 .display(Some(&func_params)) 307 .to_string(), 308 "u2:4" 309 ); 310 } 311 312 #[test] 313 fn parsing() { 314 assert_eq!( 315 "FloorF32".parse(), 316 Ok(ExternalName::LibCall(LibCall::FloorF32)) 317 ); 318 assert_eq!( 319 ExternalName::LibCall(LibCall::FloorF32) 320 .display(None) 321 .to_string(), 322 "%FloorF32" 323 ); 324 } 325 } 326