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::LibCall; 8 use core::cmp; 9 use core::fmt::{self, Write}; 10 use core::str::FromStr; 11 12 #[cfg(feature = "enable-serde")] 13 use serde::{Deserialize, Serialize}; 14 15 const TESTCASE_NAME_LENGTH: usize = 16; 16 17 /// The name of an external is either a reference to a user-defined symbol 18 /// table, or a short sequence of ascii bytes so that test cases do not have 19 /// to keep track of a symbol table. 20 /// 21 /// External names are primarily used as keys by code using Cranelift to map 22 /// from a `cranelift_codegen::ir::FuncRef` or similar to additional associated 23 /// data. 24 /// 25 /// External names can also serve as a primitive testing and debugging tool. 26 /// In particular, many `.clif` test files use function names to identify 27 /// functions. 28 #[derive(Debug, Clone, PartialEq, Eq)] 29 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 30 pub enum ExternalName { 31 /// A name in a user-defined symbol table. Cranelift does not interpret 32 /// these numbers in any way. 33 User { 34 /// Arbitrary. 35 namespace: u32, 36 /// Arbitrary. 37 index: u32, 38 }, 39 /// A test case function name of up to a hardcoded amount of ascii 40 /// characters. This is not intended to be used outside test cases. 41 TestCase { 42 /// How many of the bytes in `ascii` are valid? 43 length: u8, 44 /// Ascii bytes of the name. 45 ascii: [u8; TESTCASE_NAME_LENGTH], 46 }, 47 /// A well-known runtime library function. 48 LibCall(LibCall), 49 } 50 51 impl ExternalName { 52 /// Creates a new external name from a sequence of bytes. Caller is expected 53 /// to guarantee bytes are only ascii alphanumeric or `_`. 54 /// 55 /// # Examples 56 /// 57 /// ```rust 58 /// # use cranelift_codegen::ir::ExternalName; 59 /// // Create `ExternalName` from a string. 60 /// let name = ExternalName::testcase("hello"); 61 /// assert_eq!(name.to_string(), "%hello"); 62 /// ``` 63 pub fn testcase<T: AsRef<[u8]>>(v: T) -> Self { 64 let vec = v.as_ref(); 65 let len = cmp::min(vec.len(), TESTCASE_NAME_LENGTH); 66 let mut bytes = [0u8; TESTCASE_NAME_LENGTH]; 67 bytes[0..len].copy_from_slice(&vec[0..len]); 68 69 Self::TestCase { 70 length: len as u8, 71 ascii: bytes, 72 } 73 } 74 75 /// Create a new external name from user-provided integer indices. 76 /// 77 /// # Examples 78 /// ```rust 79 /// # use cranelift_codegen::ir::ExternalName; 80 /// // Create `ExternalName` from integer indices 81 /// let name = ExternalName::user(123, 456); 82 /// assert_eq!(name.to_string(), "u123:456"); 83 /// ``` 84 pub fn user(namespace: u32, index: u32) -> Self { 85 Self::User { namespace, index } 86 } 87 } 88 89 impl Default for ExternalName { 90 fn default() -> Self { 91 Self::user(0, 0) 92 } 93 } 94 95 impl fmt::Display for ExternalName { 96 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 97 match *self { 98 Self::User { namespace, index } => write!(f, "u{}:{}", namespace, index), 99 Self::TestCase { length, ascii } => { 100 f.write_char('%')?; 101 for byte in ascii.iter().take(length as usize) { 102 f.write_char(*byte as char)?; 103 } 104 Ok(()) 105 } 106 Self::LibCall(lc) => write!(f, "%{}", lc), 107 } 108 } 109 } 110 111 impl FromStr for ExternalName { 112 type Err = (); 113 114 fn from_str(s: &str) -> Result<Self, Self::Err> { 115 // Try to parse as a libcall name, otherwise it's a test case. 116 match s.parse() { 117 Ok(lc) => Ok(Self::LibCall(lc)), 118 Err(_) => Ok(Self::testcase(s.as_bytes())), 119 } 120 } 121 } 122 123 #[cfg(test)] 124 mod tests { 125 use super::ExternalName; 126 use crate::ir::LibCall; 127 use alloc::string::ToString; 128 use core::u32; 129 130 #[test] 131 fn display_testcase() { 132 assert_eq!(ExternalName::testcase("").to_string(), "%"); 133 assert_eq!(ExternalName::testcase("x").to_string(), "%x"); 134 assert_eq!(ExternalName::testcase("x_1").to_string(), "%x_1"); 135 assert_eq!( 136 ExternalName::testcase("longname12345678").to_string(), 137 "%longname12345678" 138 ); 139 // Constructor will silently drop bytes beyond the 16th 140 assert_eq!( 141 ExternalName::testcase("longname123456789").to_string(), 142 "%longname12345678" 143 ); 144 } 145 146 #[test] 147 fn display_user() { 148 assert_eq!(ExternalName::user(0, 0).to_string(), "u0:0"); 149 assert_eq!(ExternalName::user(1, 1).to_string(), "u1:1"); 150 assert_eq!( 151 ExternalName::user(u32::MAX, u32::MAX).to_string(), 152 "u4294967295:4294967295" 153 ); 154 } 155 156 #[test] 157 fn parsing() { 158 assert_eq!( 159 "FloorF32".parse(), 160 Ok(ExternalName::LibCall(LibCall::FloorF32)) 161 ); 162 assert_eq!( 163 ExternalName::LibCall(LibCall::FloorF32).to_string(), 164 "%FloorF32" 165 ); 166 } 167 } 168