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