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