Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/cranelift-codegen-0.91.1/src/ir/extname.rs
Line
Count
Source (jump to first uncovered line)
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
0
    pub fn testcase<T: AsRef<[u8]>>(v: T) -> Self {
37
0
        Self::Testcase(TestcaseName::new(v))
38
0
    }
39
40
    /// Create a new external name from a user-defined external function reference.
41
51.5k
    pub fn user(namespace: u32, index: u32) -> Self {
42
51.5k
        Self::User(UserExternalName::new(namespace, index))
43
51.5k
    }
<cranelift_codegen::ir::extname::UserFuncName>::user
Line
Count
Source
41
51.5k
    pub fn user(namespace: u32, index: u32) -> Self {
42
51.5k
        Self::User(UserExternalName::new(namespace, index))
43
51.5k
    }
Unexecuted instantiation: <cranelift_codegen::ir::extname::UserFuncName>::user
Unexecuted instantiation: <cranelift_codegen::ir::extname::UserFuncName>::user
44
}
45
46
impl Default for UserFuncName {
47
227k
    fn default() -> Self {
48
227k
        UserFuncName::User(UserExternalName::default())
49
227k
    }
<cranelift_codegen::ir::extname::UserFuncName as core::default::Default>::default
Line
Count
Source
47
87.8k
    fn default() -> Self {
48
87.8k
        UserFuncName::User(UserExternalName::default())
49
87.8k
    }
<cranelift_codegen::ir::extname::UserFuncName as core::default::Default>::default
Line
Count
Source
47
139k
    fn default() -> Self {
48
139k
        UserFuncName::User(UserExternalName::default())
49
139k
    }
Unexecuted instantiation: <cranelift_codegen::ir::extname::UserFuncName as core::default::Default>::default
50
}
51
52
impl fmt::Display for UserFuncName {
53
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54
0
        match self {
55
0
            UserFuncName::User(user) => user.fmt(f),
56
0
            UserFuncName::Testcase(testcase) => testcase.fmt(f),
57
        }
58
0
    }
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
51.5k
    pub fn new(namespace: u32, index: u32) -> Self {
76
51.5k
        Self { namespace, index }
77
51.5k
    }
<cranelift_codegen::ir::extname::UserExternalName>::new
Line
Count
Source
75
51.5k
    pub fn new(namespace: u32, index: u32) -> Self {
76
51.5k
        Self { namespace, index }
77
51.5k
    }
Unexecuted instantiation: <cranelift_codegen::ir::extname::UserExternalName>::new
Unexecuted instantiation: <cranelift_codegen::ir::extname::UserExternalName>::new
78
}
79
80
impl fmt::Display for UserExternalName {
81
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82
0
        write!(f, "u{}:{}", self.namespace, self.index)
83
0
    }
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
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93
0
        f.write_char('%')?;
94
0
        f.write_str(std::str::from_utf8(&self.0).unwrap())
95
0
    }
96
}
97
98
impl fmt::Debug for TestcaseName {
99
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100
0
        write!(f, "{}", self)
101
0
    }
102
}
103
104
impl TestcaseName {
105
0
    pub(crate) fn new<T: AsRef<[u8]>>(v: T) -> Self {
106
0
        Self(v.as_ref().into())
107
0
    }
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
0
    fn default() -> Self {
137
0
        Self::User(UserExternalNameRef::new(0))
138
0
    }
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
0
    pub fn testcase<T: AsRef<[u8]>>(v: T) -> Self {
154
0
        Self::TestCase(TestcaseName::new(v))
155
0
    }
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
90.6k
    pub fn user(func_ref: UserExternalNameRef) -> Self {
167
90.6k
        Self::User(func_ref)
168
90.6k
    }
<cranelift_codegen::ir::extname::ExternalName>::user
Line
Count
Source
166
90.6k
    pub fn user(func_ref: UserExternalNameRef) -> Self {
167
90.6k
        Self::User(func_ref)
168
90.6k
    }
Unexecuted instantiation: <cranelift_codegen::ir::extname::ExternalName>::user
Unexecuted instantiation: <cranelift_codegen::ir::extname::ExternalName>::user
169
170
    /// Returns a display for the current `ExternalName`, with extra context to prettify the
171
    /// output.
172
0
    pub fn display<'a>(
173
0
        &'a self,
174
0
        params: Option<&'a FunctionParameters>,
175
0
    ) -> DisplayableExternalName<'a> {
176
0
        DisplayableExternalName { name: self, params }
177
0
    }
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
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188
0
        match &self.name {
189
0
            ExternalName::User(func_ref) => {
190
0
                if let Some(params) = self.params {
191
0
                    let name = &params.user_named_funcs()[*func_ref];
192
0
                    write!(f, "u{}:{}", name.namespace, name.index)
193
                } else {
194
                    // Best effort.
195
0
                    write!(f, "{}", *func_ref)
196
                }
197
            }
198
0
            ExternalName::TestCase(testcase) => testcase.fmt(f),
199
0
            ExternalName::LibCall(lc) => write!(f, "%{}", lc),
200
0
            ExternalName::KnownSymbol(ks) => write!(f, "%{}", ks),
201
        }
202
0
    }
203
}
204
205
impl FromStr for ExternalName {
206
    type Err = ();
207
208
0
    fn from_str(s: &str) -> Result<Self, Self::Err> {
209
        // Try to parse as a known symbol
210
0
        if let Ok(ks) = s.parse() {
211
0
            return Ok(Self::KnownSymbol(ks));
212
0
        }
213
214
        // Try to parse as a libcall name
215
0
        if let Ok(lc) = s.parse() {
216
0
            return Ok(Self::LibCall(lc));
217
0
        }
218
0
219
0
        // Otherwise its a test case name
220
0
        Ok(Self::testcase(s.as_bytes()))
221
0
    }
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
}