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/// - [`null`](super::InstBuilder::null) for null reference 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))]
67pub struct Value(u32);
68entity_impl!(Value, "v");
69
70impl 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    pub fn with_number(n: u32) -> Option<Self> {
76        if n < u32::MAX / 2 {
77            Some(Self(n))
78        } else {
79            None
80        }
81    }
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))]
98pub struct Inst(u32);
99entity_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))]
119pub struct StackSlot(u32);
120entity_impl!(StackSlot, "ss");
121
122impl StackSlot {
123    /// Create a new stack slot reference from its number.
124    ///
125    /// This method is for use by the parser.
126    pub fn with_number(n: u32) -> Option<Self> {
127        if n < u32::MAX { Some(Self(n)) } else { None }
128    }
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))]
134pub struct DynamicStackSlot(u32);
135entity_impl!(DynamicStackSlot, "dss");
136
137impl DynamicStackSlot {
138    /// Create a new stack slot reference from its number.
139    ///
140    /// This method is for use by the parser.
141    pub fn with_number(n: u32) -> Option<Self> {
142        if n < u32::MAX { Some(Self(n)) } else { None }
143    }
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))]
149pub struct DynamicType(u32);
150entity_impl!(DynamicType, "dt");
151
152impl DynamicType {
153    /// Create a new dynamic type reference from its number.
154    ///
155    /// This method is for use by the parser.
156    pub fn with_number(n: u32) -> Option<Self> {
157        if n < u32::MAX { Some(Self(n)) } else { None }
158    }
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 retrieved with
174/// [`InstBuilder:global_value`](super::InstBuilder::global_value).
175///
176/// While the order is stable, it is arbitrary.
177#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
178#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
179pub struct GlobalValue(u32);
180entity_impl!(GlobalValue, "gv");
181
182impl GlobalValue {
183    /// Create a new global value reference from its number.
184    ///
185    /// This method is for use by the parser.
186    pub fn with_number(n: u32) -> Option<Self> {
187        if n < u32::MAX { Some(Self(n)) } else { None }
188    }
189}
190
191/// An opaque reference to a memory type.
192///
193/// A `MemoryType` is a descriptor of a struct layout in memory, with
194/// types and proof-carrying-code facts optionally attached to the
195/// fields.
196#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
197#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
198pub struct MemoryType(u32);
199entity_impl!(MemoryType, "mt");
200
201impl MemoryType {
202    /// Create a new memory type reference from its number.
203    ///
204    /// This method is for use by the parser.
205    pub fn with_number(n: u32) -> Option<Self> {
206        if n < u32::MAX { Some(Self(n)) } else { None }
207    }
208}
209
210/// An opaque reference to a constant.
211///
212/// You can store [`ConstantData`](super::ConstantData) in a
213/// [`ConstantPool`](super::ConstantPool) for efficient storage and retrieval.
214/// See [`ConstantPool::insert`](super::ConstantPool::insert).
215///
216/// While the order is stable, it is arbitrary and does not necessarily resemble the order in which
217/// the constants are written in the constant pool.
218#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
219#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
220pub struct Constant(u32);
221entity_impl!(Constant, "const");
222
223impl Constant {
224    /// Create a const reference from its number.
225    ///
226    /// This method is for use by the parser.
227    pub fn with_number(n: u32) -> Option<Self> {
228        if n < u32::MAX { Some(Self(n)) } else { None }
229    }
230}
231
232/// An opaque reference to an immediate.
233///
234/// Some immediates (e.g. SIMD shuffle masks) are too large to store in the
235/// [`InstructionData`](super::instructions::InstructionData) struct and therefore must be
236/// tracked separately in [`DataFlowGraph::immediates`](super::dfg::DataFlowGraph). `Immediate`
237/// provides a way to reference values stored there.
238///
239/// While the order is stable, it is arbitrary.
240#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
241#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
242pub struct Immediate(u32);
243entity_impl!(Immediate, "imm");
244
245impl Immediate {
246    /// Create an immediate reference from its number.
247    ///
248    /// This method is for use by the parser.
249    pub fn with_number(n: u32) -> Option<Self> {
250        if n < u32::MAX { Some(Self(n)) } else { None }
251    }
252}
253
254/// An opaque reference to a [jump table](https://en.wikipedia.org/wiki/Branch_table).
255///
256/// `JumpTable`s are used for indirect branching and are specialized for dense,
257/// 0-based jump offsets. If you want a jump table which doesn't start at 0,
258/// or is not contiguous, consider using a [`Switch`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.Switch.html) instead.
259///
260/// `JumpTable` are used with [`br_table`](super::InstBuilder::br_table).
261///
262/// `JumpTable`s can be created with
263/// [`create_jump_table`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_jump_table).
264///
265/// While the order is stable, it is arbitrary.
266#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
267#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
268pub struct JumpTable(u32);
269entity_impl!(JumpTable, "jt");
270
271impl JumpTable {
272    /// Create a new jump table reference from its number.
273    ///
274    /// This method is for use by the parser.
275    pub fn with_number(n: u32) -> Option<Self> {
276        if n < u32::MAX { Some(Self(n)) } else { None }
277    }
278}
279
280/// An opaque reference to another [`Function`](super::Function).
281///
282/// `FuncRef`s are used for [direct](super::InstBuilder::call) function calls
283/// and by [`func_addr`](super::InstBuilder::func_addr) for use in
284/// [indirect](super::InstBuilder::call_indirect) function calls.
285///
286/// `FuncRef`s can be created with
287///
288/// - [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
289///   for external functions
290/// - [`Module::declare_func_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_func_in_func)
291///   for functions declared elsewhere in the same native
292///   [`Module`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html)
293///
294/// While the order is stable, it is arbitrary.
295#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
296#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
297pub struct FuncRef(u32);
298entity_impl!(FuncRef, "fn");
299
300impl FuncRef {
301    /// Create a new external function reference from its number.
302    ///
303    /// This method is for use by the parser.
304    pub fn with_number(n: u32) -> Option<Self> {
305        if n < u32::MAX { Some(Self(n)) } else { None }
306    }
307}
308
309/// A reference to an `UserExternalName`, declared with `Function::declare_imported_user_function`.
310#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
311#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
312pub struct UserExternalNameRef(u32);
313entity_impl!(UserExternalNameRef, "userextname");
314
315/// An opaque reference to a function [`Signature`](super::Signature).
316///
317/// `SigRef`s are used to declare a function with
318/// [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
319/// as well as to make an [indirect function call](super::InstBuilder::call_indirect).
320///
321/// `SigRef`s can be created with
322/// [`FunctionBuilder::import_signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_signature).
323///
324/// You can retrieve the [`Signature`](super::Signature) that was used to create a `SigRef` with
325/// [`FunctionBuilder::signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.signature) or
326/// [`func.dfg.signatures`](super::dfg::DataFlowGraph::signatures).
327///
328/// While the order is stable, it is arbitrary.
329#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
330#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
331pub struct SigRef(u32);
332entity_impl!(SigRef, "sig");
333
334impl SigRef {
335    /// Create a new function signature reference from its number.
336    ///
337    /// This method is for use by the parser.
338    pub fn with_number(n: u32) -> Option<Self> {
339        if n < u32::MAX { Some(Self(n)) } else { None }
340    }
341}
342
343/// An opaque exception tag.
344///
345/// Exception tags are used to denote the identity of an exception for
346/// matching by catch-handlers in exception tables.
347///
348/// The index space is arbitrary and is given meaning only by the
349/// embedder of Cranelift. Cranelift will carry through these tags
350/// from exception tables to the handler metadata produced as output
351/// (for use by the embedder's unwinder).
352#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
353#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
354pub struct ExceptionTag(u32);
355entity_impl!(ExceptionTag, "tag");
356
357impl ExceptionTag {
358    /// Create a new exception tag from its arbitrary index.
359    ///
360    /// This method is for use by the parser.
361    pub fn with_number(n: u32) -> Option<Self> {
362        if n < u32::MAX { Some(Self(n)) } else { None }
363    }
364}
365
366/// An opaque reference to an exception table.
367///
368/// `ExceptionTable`s are used for describing exception catch handlers on
369/// `try_call` and `try_call_indirect` instructions.
370#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
371#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
372pub struct ExceptionTable(u32);
373entity_impl!(ExceptionTable, "extable");
374
375impl ExceptionTable {
376    /// Create a new exception table reference from its number.
377    ///
378    /// This method is for use by the parser.
379    pub fn with_number(n: u32) -> Option<Self> {
380        if n < u32::MAX { Some(Self(n)) } else { None }
381    }
382}
383
384/// An opaque reference to any of the entities defined in this module that can appear in CLIF IR.
385#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
386#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
387pub enum AnyEntity {
388    /// The whole function.
389    Function,
390    /// a basic block.
391    Block(Block),
392    /// An instruction.
393    Inst(Inst),
394    /// An SSA value.
395    Value(Value),
396    /// A stack slot.
397    StackSlot(StackSlot),
398    /// A dynamic stack slot.
399    DynamicStackSlot(DynamicStackSlot),
400    /// A dynamic type
401    DynamicType(DynamicType),
402    /// A Global value.
403    GlobalValue(GlobalValue),
404    /// A memory type.
405    MemoryType(MemoryType),
406    /// A jump table.
407    JumpTable(JumpTable),
408    /// A constant.
409    Constant(Constant),
410    /// An external function.
411    FuncRef(FuncRef),
412    /// A function call signature.
413    SigRef(SigRef),
414    /// An exception table.
415    ExceptionTable(ExceptionTable),
416    /// A function's stack limit
417    StackLimit,
418}
419
420impl fmt::Display for AnyEntity {
421    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
422        match *self {
423            Self::Function => write!(f, "function"),
424            Self::Block(r) => r.fmt(f),
425            Self::Inst(r) => r.fmt(f),
426            Self::Value(r) => r.fmt(f),
427            Self::StackSlot(r) => r.fmt(f),
428            Self::DynamicStackSlot(r) => r.fmt(f),
429            Self::DynamicType(r) => r.fmt(f),
430            Self::GlobalValue(r) => r.fmt(f),
431            Self::MemoryType(r) => r.fmt(f),
432            Self::JumpTable(r) => r.fmt(f),
433            Self::Constant(r) => r.fmt(f),
434            Self::FuncRef(r) => r.fmt(f),
435            Self::SigRef(r) => r.fmt(f),
436            Self::ExceptionTable(r) => r.fmt(f),
437            Self::StackLimit => write!(f, "stack_limit"),
438        }
439    }
440}
441
442impl fmt::Debug for AnyEntity {
443    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
444        (self as &dyn fmt::Display).fmt(f)
445    }
446}
447
448impl From<Block> for AnyEntity {
449    fn from(r: Block) -> Self {
450        Self::Block(r)
451    }
452}
453
454impl From<Inst> for AnyEntity {
455    fn from(r: Inst) -> Self {
456        Self::Inst(r)
457    }
458}
459
460impl From<Value> for AnyEntity {
461    fn from(r: Value) -> Self {
462        Self::Value(r)
463    }
464}
465
466impl From<StackSlot> for AnyEntity {
467    fn from(r: StackSlot) -> Self {
468        Self::StackSlot(r)
469    }
470}
471
472impl From<DynamicStackSlot> for AnyEntity {
473    fn from(r: DynamicStackSlot) -> Self {
474        Self::DynamicStackSlot(r)
475    }
476}
477
478impl From<DynamicType> for AnyEntity {
479    fn from(r: DynamicType) -> Self {
480        Self::DynamicType(r)
481    }
482}
483
484impl From<GlobalValue> for AnyEntity {
485    fn from(r: GlobalValue) -> Self {
486        Self::GlobalValue(r)
487    }
488}
489
490impl From<MemoryType> for AnyEntity {
491    fn from(r: MemoryType) -> Self {
492        Self::MemoryType(r)
493    }
494}
495
496impl From<JumpTable> for AnyEntity {
497    fn from(r: JumpTable) -> Self {
498        Self::JumpTable(r)
499    }
500}
501
502impl From<Constant> for AnyEntity {
503    fn from(r: Constant) -> Self {
504        Self::Constant(r)
505    }
506}
507
508impl From<FuncRef> for AnyEntity {
509    fn from(r: FuncRef) -> Self {
510        Self::FuncRef(r)
511    }
512}
513
514impl From<SigRef> for AnyEntity {
515    fn from(r: SigRef) -> Self {
516        Self::SigRef(r)
517    }
518}
519
520impl From<ExceptionTable> for AnyEntity {
521    fn from(r: ExceptionTable) -> Self {
522        Self::ExceptionTable(r)
523    }
524}
525
526#[cfg(test)]
527mod tests {
528    use super::*;
529    use alloc::string::ToString;
530
531    #[test]
532    fn value_with_number() {
533        assert_eq!(Value::with_number(0).unwrap().to_string(), "v0");
534        assert_eq!(Value::with_number(1).unwrap().to_string(), "v1");
535
536        assert_eq!(Value::with_number(u32::MAX / 2), None);
537        assert!(Value::with_number(u32::MAX / 2 - 1).is_some());
538    }
539
540    #[test]
541    fn memory() {
542        use crate::packed_option::PackedOption;
543        use core::mem;
544        // This is the whole point of `PackedOption`.
545        assert_eq!(
546            mem::size_of::<Value>(),
547            mem::size_of::<PackedOption<Value>>()
548        );
549    }
550
551    #[test]
552    fn memory_option() {
553        use core::mem;
554        // PackedOption is used because Option<EntityRef> is twice as large
555        // as EntityRef. If this ever fails to be the case, this test will fail.
556        assert_eq!(mem::size_of::<Value>() * 2, mem::size_of::<Option<Value>>());
557    }
558
559    #[test]
560    fn constant_with_number() {
561        assert_eq!(Constant::with_number(0).unwrap().to_string(), "const0");
562        assert_eq!(Constant::with_number(1).unwrap().to_string(), "const1");
563    }
564}