Coverage Report

Created: 2026-06-21 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasmtime/cranelift/codegen/src/ir/entities.rs
Line
Count
Source
1
//! Cranelift IR entity references.
2
//!
3
//! Instructions in Cranelift IR need to reference other entities in the function. This can be other
4
//! parts of the function like basic blocks or stack slots, or it can be external entities
5
//! that are declared in the function preamble in the text format.
6
//!
7
//! These entity references in instruction operands are not implemented as Rust references both
8
//! because Rust's ownership and mutability rules make it difficult, and because 64-bit pointers
9
//! take up a lot of space, and we want a compact in-memory representation. Instead, entity
10
//! references are structs wrapping a `u32` index into a table in the `Function` main data
11
//! structure. There is a separate index type for each entity type, so we don't lose type safety.
12
//!
13
//! The `entities` module defines public types for the entity references along with constants
14
//! representing an invalid reference. We prefer to use `Option<EntityRef>` whenever possible, but
15
//! unfortunately that type is twice as large as the 32-bit index type on its own. Thus, compact
16
//! data structures use the `PackedOption<EntityRef>` representation, while function arguments and
17
//! return values prefer the more Rust-like `Option<EntityRef>` variant.
18
//!
19
//! The entity references all implement the `Display` trait in a way that matches the textual IR
20
//! format.
21
22
use crate::entity::entity_impl;
23
use crate::ir::AliasRegion;
24
use core::fmt;
25
use core::u32;
26
#[cfg(feature = "enable-serde")]
27
use serde_derive::{Deserialize, Serialize};
28
29
/// An opaque reference to a [basic block](https://en.wikipedia.org/wiki/Basic_block) in a
30
/// [`Function`](super::function::Function).
31
///
32
/// You can get a `Block` using
33
/// [`FunctionBuilder::create_block`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_block)
34
///
35
/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order.
36
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
37
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
38
pub struct Block(u32);
39
entity_impl!(Block, "block");
40
41
impl Block {
42
    /// Create a new block reference from its number. This corresponds to the `blockNN` representation.
43
    ///
44
    /// This method is for use by the parser.
45
186k
    pub fn with_number(n: u32) -> Option<Self> {
46
186k
        if n < u32::MAX { Some(Self(n)) } else { None }
47
186k
    }
48
}
49
50
/// An opaque reference to an SSA value.
51
///
52
/// You can get a constant `Value` from the following
53
/// [`InstBuilder`](super::InstBuilder) instructions:
54
///
55
/// - [`iconst`](super::InstBuilder::iconst) for integer constants
56
/// - [`f16const`](super::InstBuilder::f16const) for 16-bit float constants
57
/// - [`f32const`](super::InstBuilder::f32const) for 32-bit float constants
58
/// - [`f64const`](super::InstBuilder::f64const) for 64-bit float constants
59
/// - [`f128const`](super::InstBuilder::f128const) for 128-bit float constants
60
/// - [`vconst`](super::InstBuilder::vconst) for vector constants
61
///
62
/// Any `InstBuilder` instruction that has an output will also return a `Value`.
63
///
64
/// While the order is stable, it is arbitrary.
65
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
66
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
67
pub struct Value(u32);
68
entity_impl!(Value, "v");
69
70
impl Value {
71
    /// Create a value from its number representation.
72
    /// This is the number in the `vNN` notation.
73
    ///
74
    /// This method is for use by the parser.
75
0
    pub fn with_number(n: u32) -> Option<Self> {
76
0
        if n < u32::MAX / 2 {
77
0
            Some(Self(n))
78
        } else {
79
0
            None
80
        }
81
0
    }
82
}
83
84
/// An opaque reference to an instruction in a [`Function`](super::Function).
85
///
86
/// Most usage of `Inst` is internal. `Inst`ructions are returned by
87
/// [`InstBuilder`](super::InstBuilder) instructions that do not return a
88
/// [`Value`], such as control flow and trap instructions, as well as instructions that return a
89
/// variable (potentially zero!) number of values, like call or call-indirect instructions. To get
90
/// the `Value` of such instructions, use [`inst_results`](super::DataFlowGraph::inst_results) or
91
/// its analogue in `cranelift_frontend::FuncBuilder`.
92
///
93
/// [inst_comment]: https://github.com/bjorn3/rustc_codegen_cranelift/blob/0f8814fd6da3d436a90549d4bb19b94034f2b19c/src/pretty_clif.rs
94
///
95
/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order.
96
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
97
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
98
pub struct Inst(u32);
99
entity_impl!(Inst, "inst");
100
101
/// An opaque reference to a stack slot.
102
///
103
/// Stack slots represent an address on the
104
/// [call stack](https://en.wikipedia.org/wiki/Call_stack).
105
///
106
/// `StackSlot`s can be created with
107
/// [`FunctionBuilder::create_sized_stack_slot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_sized_stack_slot)
108
/// or
109
/// [`FunctionBuilder::create_dynamic_stack_slot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_dynamic_stack_slot).
110
///
111
/// `StackSlot`s are most often used with
112
/// [`stack_addr`](super::InstBuilder::stack_addr),
113
/// [`stack_load`](super::InstBuilder::stack_load), and
114
/// [`stack_store`](super::InstBuilder::stack_store).
115
///
116
/// While the order is stable, it is arbitrary and does not necessarily resemble the stack order.
117
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
118
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
119
pub struct StackSlot(u32);
120
entity_impl!(StackSlot, "ss");
121
122
impl StackSlot {
123
    /// Create a new stack slot reference from its number.
124
    ///
125
    /// This method is for use by the parser.
126
0
    pub fn with_number(n: u32) -> Option<Self> {
127
0
        if n < u32::MAX { Some(Self(n)) } else { None }
128
0
    }
129
}
130
131
/// An opaque reference to a dynamic stack slot.
132
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
133
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
134
pub struct DynamicStackSlot(u32);
135
entity_impl!(DynamicStackSlot, "dss");
136
137
impl DynamicStackSlot {
138
    /// Create a new stack slot reference from its number.
139
    ///
140
    /// This method is for use by the parser.
141
0
    pub fn with_number(n: u32) -> Option<Self> {
142
0
        if n < u32::MAX { Some(Self(n)) } else { None }
143
0
    }
144
}
145
146
/// An opaque reference to a dynamic type.
147
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
148
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
149
pub struct DynamicType(u32);
150
entity_impl!(DynamicType, "dt");
151
152
impl DynamicType {
153
    /// Create a new dynamic type reference from its number.
154
    ///
155
    /// This method is for use by the parser.
156
0
    pub fn with_number(n: u32) -> Option<Self> {
157
0
        if n < u32::MAX { Some(Self(n)) } else { None }
158
0
    }
159
}
160
161
/// An opaque reference to a global value.
162
///
163
/// A `GlobalValue` is a [`Value`] that will be live across the entire
164
/// function lifetime. It can be preloaded from other global values.
165
///
166
/// You can create a `GlobalValue` in the following ways:
167
///
168
/// - When compiling to native code, you can use it for objects in static memory with
169
///   [`Module::declare_data_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_data_in_func).
170
/// - For any compilation target, it can be registered with
171
///   [`FunctionBuilder::create_global_value`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_global_value).
172
///
173
/// `GlobalValue`s can be referenced from a function's body with
174
/// [`InstBuilder::symbol_value`](super::InstBuilder::symbol_value) and
175
/// [`InstBuilder::tls_value`](super::InstBuilder::tls_value).
176
///
177
/// While the order is stable, it is arbitrary.
178
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
179
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
180
pub struct GlobalValue(u32);
181
entity_impl!(GlobalValue, "gv");
182
183
impl GlobalValue {
184
    /// Create a new global value reference from its number.
185
    ///
186
    /// This method is for use by the parser.
187
0
    pub fn with_number(n: u32) -> Option<Self> {
188
0
        if n < u32::MAX { Some(Self(n)) } else { None }
189
0
    }
190
}
191
192
/// An opaque reference to a constant.
193
///
194
/// You can store [`ConstantData`](super::ConstantData) in a
195
/// [`ConstantPool`](super::ConstantPool) for efficient storage and retrieval.
196
/// See [`ConstantPool::insert`](super::ConstantPool::insert).
197
///
198
/// While the order is stable, it is arbitrary and does not necessarily resemble the order in which
199
/// the constants are written in the constant pool.
200
#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
201
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
202
pub struct Constant(u32);
203
entity_impl!(Constant, "const");
204
205
impl Constant {
206
    /// Create a const reference from its number.
207
    ///
208
    /// This method is for use by the parser.
209
0
    pub fn with_number(n: u32) -> Option<Self> {
210
0
        if n < u32::MAX { Some(Self(n)) } else { None }
211
0
    }
212
}
213
214
/// An opaque reference to an immediate.
215
///
216
/// Some immediates (e.g. SIMD shuffle masks) are too large to store in the
217
/// [`InstructionData`](super::instructions::InstructionData) struct and therefore must be
218
/// tracked separately in [`DataFlowGraph::immediates`](super::dfg::DataFlowGraph). `Immediate`
219
/// provides a way to reference values stored there.
220
///
221
/// While the order is stable, it is arbitrary.
222
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
223
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
224
pub struct Immediate(u32);
225
entity_impl!(Immediate, "imm");
226
227
impl Immediate {
228
    /// Create an immediate reference from its number.
229
    ///
230
    /// This method is for use by the parser.
231
0
    pub fn with_number(n: u32) -> Option<Self> {
232
0
        if n < u32::MAX { Some(Self(n)) } else { None }
233
0
    }
234
}
235
236
/// An opaque reference to a [jump table](https://en.wikipedia.org/wiki/Branch_table).
237
///
238
/// `JumpTable`s are used for indirect branching and are specialized for dense,
239
/// 0-based jump offsets. If you want a jump table which doesn't start at 0,
240
/// or is not contiguous, consider using a [`Switch`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.Switch.html) instead.
241
///
242
/// `JumpTable` are used with [`br_table`](super::InstBuilder::br_table).
243
///
244
/// `JumpTable`s can be created with
245
/// [`create_jump_table`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_jump_table).
246
///
247
/// While the order is stable, it is arbitrary.
248
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
249
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
250
pub struct JumpTable(u32);
251
entity_impl!(JumpTable, "jt");
252
253
impl JumpTable {
254
    /// Create a new jump table reference from its number.
255
    ///
256
    /// This method is for use by the parser.
257
0
    pub fn with_number(n: u32) -> Option<Self> {
258
0
        if n < u32::MAX { Some(Self(n)) } else { None }
259
0
    }
260
}
261
262
/// An opaque reference to another [`Function`](super::Function).
263
///
264
/// `FuncRef`s are used for [direct](super::InstBuilder::call) function calls
265
/// and by [`func_addr`](super::InstBuilder::func_addr) for use in
266
/// [indirect](super::InstBuilder::call_indirect) function calls.
267
///
268
/// `FuncRef`s can be created with
269
///
270
/// - [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
271
///   for external functions
272
/// - [`Module::declare_func_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_func_in_func)
273
///   for functions declared elsewhere in the same native
274
///   [`Module`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html)
275
///
276
/// While the order is stable, it is arbitrary.
277
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
278
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
279
pub struct FuncRef(u32);
280
entity_impl!(FuncRef, "fn");
281
282
impl FuncRef {
283
    /// Create a new external function reference from its number.
284
    ///
285
    /// This method is for use by the parser.
286
0
    pub fn with_number(n: u32) -> Option<Self> {
287
0
        if n < u32::MAX { Some(Self(n)) } else { None }
288
0
    }
289
}
290
291
/// A reference to an `UserExternalName`, declared with `Function::declare_imported_user_function`.
292
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
293
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
294
pub struct UserExternalNameRef(u32);
295
entity_impl!(UserExternalNameRef, "userextname");
296
297
/// An opaque reference to a function [`Signature`](super::Signature).
298
///
299
/// `SigRef`s are used to declare a function with
300
/// [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
301
/// as well as to make an [indirect function call](super::InstBuilder::call_indirect).
302
///
303
/// `SigRef`s can be created with
304
/// [`FunctionBuilder::import_signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_signature).
305
///
306
/// You can retrieve the [`Signature`](super::Signature) that was used to create a `SigRef` with
307
/// [`FunctionBuilder::signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.signature) or
308
/// [`func.dfg.signatures`](super::dfg::DataFlowGraph::signatures).
309
///
310
/// While the order is stable, it is arbitrary.
311
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
312
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
313
pub struct SigRef(u32);
314
entity_impl!(SigRef, "sig");
315
316
impl SigRef {
317
    /// Create a new function signature reference from its number.
318
    ///
319
    /// This method is for use by the parser.
320
0
    pub fn with_number(n: u32) -> Option<Self> {
321
0
        if n < u32::MAX { Some(Self(n)) } else { None }
322
0
    }
323
}
324
325
/// An opaque exception tag.
326
///
327
/// Exception tags are used to denote the identity of an exception for
328
/// matching by catch-handlers in exception tables.
329
///
330
/// The index space is arbitrary and is given meaning only by the
331
/// embedder of Cranelift. Cranelift will carry through these tags
332
/// from exception tables to the handler metadata produced as output
333
/// (for use by the embedder's unwinder).
334
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
335
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
336
pub struct ExceptionTag(u32);
337
entity_impl!(ExceptionTag, "tag");
338
339
impl ExceptionTag {
340
    /// Create a new exception tag from its arbitrary index.
341
    ///
342
    /// This method is for use by the parser.
343
0
    pub fn with_number(n: u32) -> Option<Self> {
344
0
        if n < u32::MAX { Some(Self(n)) } else { None }
345
0
    }
346
}
347
348
/// An opaque reference to an exception table.
349
///
350
/// `ExceptionTable`s are used for describing exception catch handlers on
351
/// `try_call` and `try_call_indirect` instructions.
352
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
353
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
354
pub struct ExceptionTable(u32);
355
entity_impl!(ExceptionTable, "extable");
356
357
impl ExceptionTable {
358
    /// Create a new exception table reference from its number.
359
    ///
360
    /// This method is for use by the parser.
361
0
    pub fn with_number(n: u32) -> Option<Self> {
362
0
        if n < u32::MAX { Some(Self(n)) } else { None }
363
0
    }
364
}
365
366
/// An opaque reference to any of the entities defined in this module that can appear in CLIF IR.
367
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
368
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
369
pub enum AnyEntity {
370
    /// The whole function.
371
    Function,
372
    /// a basic block.
373
    Block(Block),
374
    /// An instruction.
375
    Inst(Inst),
376
    /// An SSA value.
377
    Value(Value),
378
    /// A stack slot.
379
    StackSlot(StackSlot),
380
    /// A dynamic stack slot.
381
    DynamicStackSlot(DynamicStackSlot),
382
    /// A dynamic type
383
    DynamicType(DynamicType),
384
    /// A Global value.
385
    GlobalValue(GlobalValue),
386
    /// A jump table.
387
    JumpTable(JumpTable),
388
    /// A constant.
389
    Constant(Constant),
390
    /// An external function.
391
    FuncRef(FuncRef),
392
    /// A function call signature.
393
    SigRef(SigRef),
394
    /// An exception table.
395
    ExceptionTable(ExceptionTable),
396
    /// An alias region.
397
    AliasRegion(AliasRegion),
398
    /// A function's stack limit
399
    StackLimit,
400
}
401
402
impl fmt::Display for AnyEntity {
403
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
404
0
        match *self {
405
0
            Self::Function => write!(f, "function"),
406
0
            Self::Block(r) => r.fmt(f),
407
0
            Self::Inst(r) => r.fmt(f),
408
0
            Self::Value(r) => r.fmt(f),
409
0
            Self::StackSlot(r) => r.fmt(f),
410
0
            Self::DynamicStackSlot(r) => r.fmt(f),
411
0
            Self::DynamicType(r) => r.fmt(f),
412
0
            Self::GlobalValue(r) => r.fmt(f),
413
0
            Self::JumpTable(r) => r.fmt(f),
414
0
            Self::Constant(r) => r.fmt(f),
415
0
            Self::FuncRef(r) => r.fmt(f),
416
0
            Self::SigRef(r) => r.fmt(f),
417
0
            Self::ExceptionTable(r) => r.fmt(f),
418
0
            Self::AliasRegion(r) => r.fmt(f),
419
0
            Self::StackLimit => write!(f, "stack_limit"),
420
        }
421
0
    }
422
}
423
424
impl fmt::Debug for AnyEntity {
425
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
426
0
        (self as &dyn fmt::Display).fmt(f)
427
0
    }
428
}
429
430
impl From<Block> for AnyEntity {
431
0
    fn from(r: Block) -> Self {
432
0
        Self::Block(r)
433
0
    }
434
}
435
436
impl From<Inst> for AnyEntity {
437
0
    fn from(r: Inst) -> Self {
438
0
        Self::Inst(r)
439
0
    }
440
}
441
442
impl From<Value> for AnyEntity {
443
0
    fn from(r: Value) -> Self {
444
0
        Self::Value(r)
445
0
    }
446
}
447
448
impl From<StackSlot> for AnyEntity {
449
0
    fn from(r: StackSlot) -> Self {
450
0
        Self::StackSlot(r)
451
0
    }
452
}
453
454
impl From<DynamicStackSlot> for AnyEntity {
455
0
    fn from(r: DynamicStackSlot) -> Self {
456
0
        Self::DynamicStackSlot(r)
457
0
    }
458
}
459
460
impl From<DynamicType> for AnyEntity {
461
0
    fn from(r: DynamicType) -> Self {
462
0
        Self::DynamicType(r)
463
0
    }
464
}
465
466
impl From<GlobalValue> for AnyEntity {
467
0
    fn from(r: GlobalValue) -> Self {
468
0
        Self::GlobalValue(r)
469
0
    }
470
}
471
472
impl From<JumpTable> for AnyEntity {
473
0
    fn from(r: JumpTable) -> Self {
474
0
        Self::JumpTable(r)
475
0
    }
476
}
477
478
impl From<Constant> for AnyEntity {
479
0
    fn from(r: Constant) -> Self {
480
0
        Self::Constant(r)
481
0
    }
482
}
483
484
impl From<FuncRef> for AnyEntity {
485
0
    fn from(r: FuncRef) -> Self {
486
0
        Self::FuncRef(r)
487
0
    }
488
}
489
490
impl From<SigRef> for AnyEntity {
491
0
    fn from(r: SigRef) -> Self {
492
0
        Self::SigRef(r)
493
0
    }
494
}
495
496
impl From<ExceptionTable> for AnyEntity {
497
0
    fn from(r: ExceptionTable) -> Self {
498
0
        Self::ExceptionTable(r)
499
0
    }
500
}
501
502
impl From<AliasRegion> for AnyEntity {
503
0
    fn from(r: AliasRegion) -> Self {
504
0
        Self::AliasRegion(r)
505
0
    }
506
}
507
508
#[cfg(test)]
509
mod tests {
510
    use super::*;
511
    use alloc::string::ToString;
512
513
    #[test]
514
    fn value_with_number() {
515
        assert_eq!(Value::with_number(0).unwrap().to_string(), "v0");
516
        assert_eq!(Value::with_number(1).unwrap().to_string(), "v1");
517
518
        assert_eq!(Value::with_number(u32::MAX / 2), None);
519
        assert!(Value::with_number(u32::MAX / 2 - 1).is_some());
520
    }
521
522
    #[test]
523
    fn memory() {
524
        use crate::packed_option::PackedOption;
525
        use core::mem;
526
        // This is the whole point of `PackedOption`.
527
        assert_eq!(
528
            mem::size_of::<Value>(),
529
            mem::size_of::<PackedOption<Value>>()
530
        );
531
    }
532
533
    #[test]
534
    fn memory_option() {
535
        use core::mem;
536
        // PackedOption is used because Option<EntityRef> is twice as large
537
        // as EntityRef. If this ever fails to be the case, this test will fail.
538
        assert_eq!(mem::size_of::<Value>() * 2, mem::size_of::<Option<Value>>());
539
    }
540
541
    #[test]
542
    fn constant_with_number() {
543
        assert_eq!(Constant::with_number(0).unwrap().to_string(), "const0");
544
        assert_eq!(Constant::with_number(1).unwrap().to_string(), "const1");
545
    }
546
}