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 = &params.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