/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 = ¶ms.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 | | } |