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::{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/// - [`f32const`](super::InstBuilder::f32const) for 32-bit float constants
60/// - [`f64const`](super::InstBuilder::f64const) for 64-bit float constants
61/// - [`vconst`](super::InstBuilder::vconst) for vector constants
62/// - [`null`](super::InstBuilder::null) for null reference constants
63///
64/// Any `InstBuilder` instruction that has an output will also return a `Value`.
65///
66/// While the order is stable, it is arbitrary.
67#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
68#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
69pub struct Value(u32);
70entity_impl!(Value, "v");
71
72impl Value {
73 /// Create a value from its number representation.
74 /// This is the number in the `vNN` notation.
75 ///
76 /// This method is for use by the parser.
77 pub fn with_number(n: u32) -> Option<Self> {
78 if n < u32::MAX / 2 {
79 Some(Self(n))
80 } else {
81 None
82 }
83 }
84}
85
86/// An opaque reference to an instruction in a [`Function`](super::Function).
87///
88/// Most usage of `Inst` is internal. `Inst`ructions are returned by
89/// [`InstBuilder`](super::InstBuilder) instructions that do not return a
90/// [`Value`], such as control flow and trap instructions, as well as instructions that return a
91/// variable (potentially zero!) number of values, like call or call-indirect instructions. To get
92/// the `Value` of such instructions, use [`inst_results`](super::DataFlowGraph::inst_results) or
93/// its analogue in `cranelift_frontend::FuncBuilder`.
94///
95/// [inst_comment]: https://github.com/bjorn3/rustc_codegen_cranelift/blob/0f8814fd6da3d436a90549d4bb19b94034f2b19c/src/pretty_clif.rs
96///
97/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order.
98#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
99#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
100pub struct Inst(u32);
101entity_impl!(Inst, "inst");
102
103/// An opaque reference to a stack slot.
104///
105/// Stack slots represent an address on the
106/// [call stack](https://en.wikipedia.org/wiki/Call_stack).
107///
108/// `StackSlot`s can be created with
109/// [`FunctionBuilder::create_stackslot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_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 {
128 Some(Self(n))
129 } else {
130 None
131 }
132 }
133}
134
135/// An opaque reference to a dynamic stack slot.
136#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
137#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
138pub struct DynamicStackSlot(u32);
139entity_impl!(DynamicStackSlot, "dss");
140
141impl DynamicStackSlot {
142 /// Create a new stack slot reference from its number.
143 ///
144 /// This method is for use by the parser.
145 pub fn with_number(n: u32) -> Option<Self> {
146 if n < u32::MAX {
147 Some(Self(n))
148 } else {
149 None
150 }
151 }
152}
153
154/// An opaque reference to a dynamic type.
155#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
156#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
157pub struct DynamicType(u32);
158entity_impl!(DynamicType, "dt");
159
160impl DynamicType {
161 /// Create a new dynamic type reference from its number.
162 ///
163 /// This method is for use by the parser.
164 pub fn with_number(n: u32) -> Option<Self> {
165 if n < u32::MAX {
166 Some(Self(n))
167 } else {
168 None
169 }
170 }
171}
172
173/// An opaque reference to a global value.
174///
175/// A `GlobalValue` is a [`Value`](Value) that will be live across the entire
176/// function lifetime. It can be preloaded from other global values.
177///
178/// You can create a `GlobalValue` in the following ways:
179///
180/// - When compiling to WASM, you can use it to load values from a
181/// [`VmContext`](super::GlobalValueData::VMContext) using
182/// [`FuncEnvironment::make_global`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_global).
183/// - When compiling to native code, you can use it for objects in static memory with
184/// [`Module::declare_data_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_data_in_func).
185/// - For any compilation target, it can be registered with
186/// [`FunctionBuilder::create_global_value`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_global_value).
187///
188/// `GlobalValue`s can be retrieved with
189/// [`InstBuilder:global_value`](super::InstBuilder::global_value).
190///
191/// While the order is stable, it is arbitrary.
192#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
193#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
194pub struct GlobalValue(u32);
195entity_impl!(GlobalValue, "gv");
196
197impl GlobalValue {
198 /// Create a new global value reference from its number.
199 ///
200 /// This method is for use by the parser.
201 pub fn with_number(n: u32) -> Option<Self> {
202 if n < u32::MAX {
203 Some(Self(n))
204 } else {
205 None
206 }
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 {
229 Some(Self(n))
230 } else {
231 None
232 }
233 }
234}
235
236/// An opaque reference to an immediate.
237///
238/// Some immediates (e.g. SIMD shuffle masks) are too large to store in the
239/// [`InstructionData`](super::instructions::InstructionData) struct and therefore must be
240/// tracked separately in [`DataFlowGraph::immediates`](super::dfg::DataFlowGraph). `Immediate`
241/// provides a way to reference values stored there.
242///
243/// While the order is stable, it is arbitrary.
244#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
245#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
246pub struct Immediate(u32);
247entity_impl!(Immediate, "imm");
248
249impl Immediate {
250 /// Create an immediate reference from its number.
251 ///
252 /// This method is for use by the parser.
253 pub fn with_number(n: u32) -> Option<Self> {
254 if n < u32::MAX {
255 Some(Self(n))
256 } else {
257 None
258 }
259 }
260}
261
262/// An opaque reference to a [jump table](https://en.wikipedia.org/wiki/Branch_table).
263///
264/// `JumpTable`s are used for indirect branching and are specialized for dense,
265/// 0-based jump offsets. If you want a jump table which doesn't start at 0,
266/// or is not contiguous, consider using a [`Switch`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.Switch.html) instead.
267///
268/// `JumpTable` are used with [`br_table`](super::InstBuilder::br_table).
269///
270/// `JumpTable`s can be created with
271/// [`create_jump_table`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_jump_table).
272///
273/// While the order is stable, it is arbitrary.
274#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
275#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
276pub struct JumpTable(u32);
277entity_impl!(JumpTable, "jt");
278
279impl JumpTable {
280 /// Create a new jump table reference from its number.
281 ///
282 /// This method is for use by the parser.
283 pub fn with_number(n: u32) -> Option<Self> {
284 if n < u32::MAX {
285 Some(Self(n))
286 } else {
287 None
288 }
289 }
290}
291
292/// An opaque reference to another [`Function`](super::Function).
293///
294/// `FuncRef`s are used for [direct](super::InstBuilder::call) function calls
295/// and by [`func_addr`](super::InstBuilder::func_addr) for use in
296/// [indirect](super::InstBuilder::call_indirect) function calls.
297///
298/// `FuncRef`s can be created with
299///
300/// - [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
301/// for external functions
302/// - [`Module::declare_func_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_func_in_func)
303/// for functions declared elsewhere in the same native
304/// [`Module`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html)
305/// - [`FuncEnvironment::make_direct_func`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_direct_func)
306/// for functions declared in the same WebAssembly
307/// [`FuncEnvironment`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_direct_func)
308///
309/// While the order is stable, it is arbitrary.
310#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
311#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
312pub struct FuncRef(u32);
313entity_impl!(FuncRef, "fn");
314
315impl FuncRef {
316 /// Create a new external function reference from its number.
317 ///
318 /// This method is for use by the parser.
319 pub fn with_number(n: u32) -> Option<Self> {
320 if n < u32::MAX {
321 Some(Self(n))
322 } else {
323 None
324 }
325 }
326}
327
328/// A reference to an `UserExternalName`, declared with `Function::declare_imported_user_function`.
329#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
330#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
331pub struct UserExternalNameRef(u32);
332entity_impl!(UserExternalNameRef, "userextname");
333
334/// An opaque reference to a function [`Signature`](super::Signature).
335///
336/// `SigRef`s are used to declare a function with
337/// [`FunctionBuiler::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
338/// as well as to make an [indirect function call](super::InstBuilder::call_indirect).
339///
340/// `SigRef`s can be created with
341/// [`FunctionBuilder::import_signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_signature).
342///
343/// You can retrieve the [`Signature`](super::Signature) that was used to create a `SigRef` with
344/// [`FunctionBuilder::signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.signature) or
345/// [`func.dfg.signatures`](super::dfg::DataFlowGraph::signatures).
346///
347/// While the order is stable, it is arbitrary.
348#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
349#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
350pub struct SigRef(u32);
351entity_impl!(SigRef, "sig");
352
353impl SigRef {
354 /// Create a new function signature reference from its number.
355 ///
356 /// This method is for use by the parser.
357 pub fn with_number(n: u32) -> Option<Self> {
358 if n < u32::MAX {
359 Some(Self(n))
360 } else {
361 None
362 }
363 }
364}
365
366/// An opaque reference to a [WebAssembly
367/// table](https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format#WebAssembly_tables).
368///
369/// `Table`s are used to store a list of function references.
370/// They can be created with [`FuncEnvironment::make_table`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_table).
371/// They can be used with
372/// [`FuncEnvironment::translate_call_indirect`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.translate_call_indirect).
373///
374/// While the order is stable, it is arbitrary.
375#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
376#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
377pub struct Table(u32);
378entity_impl!(Table, "table");
379
380impl Table {
381 /// Create a new table reference from its number.
382 ///
383 /// This method is for use by the parser.
384 pub fn with_number(n: u32) -> Option<Self> {
385 if n < u32::MAX {
386 Some(Self(n))
387 } else {
388 None
389 }
390 }
391}
392
393/// An opaque reference to any of the entities defined in this module that can appear in CLIF IR.
394#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
395#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
396pub enum AnyEntity {
397 /// The whole function.
398 Function,
399 /// a basic block.
400 Block(Block),
401 /// An instruction.
402 Inst(Inst),
403 /// An SSA value.
404 Value(Value),
405 /// A stack slot.
406 StackSlot(StackSlot),
407 /// A dynamic stack slot.
408 DynamicStackSlot(DynamicStackSlot),
409 /// A dynamic type
410 DynamicType(DynamicType),
411 /// A Global value.
412 GlobalValue(GlobalValue),
413 /// A jump table.
414 JumpTable(JumpTable),
415 /// A constant.
416 Constant(Constant),
417 /// An external function.
418 FuncRef(FuncRef),
419 /// A function call signature.
420 SigRef(SigRef),
421 /// A table.
422 Table(Table),
423 /// A function's stack limit
424 StackLimit,
425}
426
427impl fmt::Display for AnyEntity {
428 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
429 match *self {
430 Self::Function => write!(f, "function"),
431 Self::Block(r) => r.fmt(f),
432 Self::Inst(r) => r.fmt(f),
433 Self::Value(r) => r.fmt(f),
434 Self::StackSlot(r) => r.fmt(f),
435 Self::DynamicStackSlot(r) => r.fmt(f),
436 Self::DynamicType(r) => r.fmt(f),
437 Self::GlobalValue(r) => r.fmt(f),
438 Self::JumpTable(r) => r.fmt(f),
439 Self::Constant(r) => r.fmt(f),
440 Self::FuncRef(r) => r.fmt(f),
441 Self::SigRef(r) => r.fmt(f),
442 Self::Table(r) => r.fmt(f),
443 Self::StackLimit => write!(f, "stack_limit"),
444 }
445 }
446}
447
448impl fmt::Debug for AnyEntity {
449 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
450 (self as &dyn fmt::Display).fmt(f)
451 }
452}
453
454impl From<Block> for AnyEntity {
455 fn from(r: Block) -> Self {
456 Self::Block(r)
457 }
458}
459
460impl From<Inst> for AnyEntity {
461 fn from(r: Inst) -> Self {
462 Self::Inst(r)
463 }
464}
465
466impl From<Value> for AnyEntity {
467 fn from(r: Value) -> Self {
468 Self::Value(r)
469 }
470}
471
472impl From<StackSlot> for AnyEntity {
473 fn from(r: StackSlot) -> Self {
474 Self::StackSlot(r)
475 }
476}
477
478impl From<DynamicStackSlot> for AnyEntity {
479 fn from(r: DynamicStackSlot) -> Self {
480 Self::DynamicStackSlot(r)
481 }
482}
483
484impl From<DynamicType> for AnyEntity {
485 fn from(r: DynamicType) -> Self {
486 Self::DynamicType(r)
487 }
488}
489
490impl From<GlobalValue> for AnyEntity {
491 fn from(r: GlobalValue) -> Self {
492 Self::GlobalValue(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<Table> for AnyEntity {
521 fn from(r: Table) -> Self {
522 Self::Table(r)
523 }
524}
525
526#[cfg(test)]
527mod tests {
528 use super::*;
529 use alloc::string::ToString;
530 use core::u32;
531
532 #[test]
533 fn value_with_number() {
534 assert_eq!(Value::with_number(0).unwrap().to_string(), "v0");
535 assert_eq!(Value::with_number(1).unwrap().to_string(), "v1");
536
537 assert_eq!(Value::with_number(u32::MAX / 2), None);
538 assert!(Value::with_number(u32::MAX / 2 - 1).is_some());
539 }
540
541 #[test]
542 fn memory() {
543 use crate::packed_option::PackedOption;
544 use core::mem;
545 // This is the whole point of `PackedOption`.
546 assert_eq!(
547 mem::size_of::<Value>(),
548 mem::size_of::<PackedOption<Value>>()
549 );
550 }
551
552 #[test]
553 fn constant_with_number() {
554 assert_eq!(Constant::with_number(0).unwrap().to_string(), "const0");
555 assert_eq!(Constant::with_number(1).unwrap().to_string(), "const1");
556 }
557}