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