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