Skip to main content

cranelift_codegen/ir/
entities.rs

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