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