Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/ir/extname.rs
1693 views
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 `_`.
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
54
impl Default for UserFuncName {
55
fn default() -> Self {
56
UserFuncName::User(UserExternalName::default())
57
}
58
}
59
60
impl 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))]
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].
83
pub fn new(namespace: u32, index: u32) -> Self {
84
Self { namespace, index }
85
}
86
}
87
88
impl 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))]
97
pub struct TestcaseName(Box<[u8]>);
98
99
impl 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
106
impl fmt::Debug for TestcaseName {
107
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108
write!(f, "{self}")
109
}
110
}
111
112
impl 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))]
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 {
149
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
/// ```
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.
194
pub struct DisplayableExternalName<'a> {
195
name: &'a ExternalName,
196
params: Option<&'a FunctionParameters>,
197
}
198
199
impl<'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
218
impl 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)]
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]
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
}
339
340