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