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    /// Get the raw test case name as bytes.
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))]
136pub 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
148impl Default for ExternalName {
149    fn default() -> Self {
150        Self::User(UserExternalNameRef::new(0))
151    }
152}
153
154impl 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    /// ```
166    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    /// ```
179    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.
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.
194pub struct DisplayableExternalName<'a> {
195    name: &'a ExternalName,
196    params: Option<&'a FunctionParameters>,
197}
198
199impl<'a> fmt::Display for DisplayableExternalName<'a> {
200    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
218impl FromStr for ExternalName {
219    type Err = ();
220
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)]
238mod 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]
249    fn externalname_size() {
250        assert_eq!(core::mem::size_of::<ExternalName>(), 24);
251    }
252
253    #[test]
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]
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]
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}