cranelift_codegen/ir/
extname.rs

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
7use crate::ir::{KnownSymbol, LibCall};
8use alloc::boxed::Box;
9use core::fmt::{self, Write};
10use core::str::FromStr;
11
12use cranelift_entity::EntityRef as _;
13#[cfg(feature = "enable-serde")]
14use serde_derive::{Deserialize, Serialize};
15
16use super::entities::UserExternalNameRef;
17use 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))]
26pub 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
33impl 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
54impl Default for UserFuncName {
55    fn default() -> Self {
56        UserFuncName::User(UserExternalName::default())
57    }
58}
59
60impl 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))]
74pub struct UserExternalName {
75    /// Arbitrary.
76    pub namespace: u32,
77    /// Arbitrary.
78    pub index: u32,
79}
80
81impl UserExternalName {
82    /// Creates a new [UserExternalName].
83    pub fn new(namespace: u32, index: u32) -> Self {
84        Self { namespace, index }
85    }
86}
87
88impl 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))]
97pub struct TestcaseName(Box<[u8]>);
98
99impl 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
106impl fmt::Debug for TestcaseName {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        write!(f, "{self}")
109    }
110}
111
112impl 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))]
131pub 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
143impl Default for ExternalName {
144    fn default() -> Self {
145        Self::User(UserExternalNameRef::new(0))
146    }
147}
148
149impl 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.
189pub struct DisplayableExternalName<'a> {
190    name: &'a ExternalName,
191    params: Option<&'a FunctionParameters>,
192}
193
194impl<'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
213impl 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)]
233mod 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}