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 crate::ir::AliasRegion;
24use core::fmt;
25use core::u32;
26#[cfg(feature = "enable-serde")]
27use 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))]
38pub struct Block(u32);
39entity_impl!(Block, "block");
40
41impl 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 pub fn with_number(n: u32) -> Option<Self> {
46 if n < u32::MAX { Some(Self(n)) } else { None }
47 }
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))]
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 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))]
180pub struct GlobalValue(u32);
181entity_impl!(GlobalValue, "gv");
182
183impl GlobalValue {
184 /// Create a new global value reference from its number.
185 ///
186 /// This method is for use by the parser.
187 pub fn with_number(n: u32) -> Option<Self> {
188 if n < u32::MAX { Some(Self(n)) } else { None }
189 }
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))]
202pub struct Constant(u32);
203entity_impl!(Constant, "const");
204
205impl Constant {
206 /// Create a const reference from its number.
207 ///
208 /// This method is for use by the parser.
209 pub fn with_number(n: u32) -> Option<Self> {
210 if n < u32::MAX { Some(Self(n)) } else { None }
211 }
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))]
224pub struct Immediate(u32);
225entity_impl!(Immediate, "imm");
226
227impl Immediate {
228 /// Create an immediate reference from its number.
229 ///
230 /// This method is for use by the parser.
231 pub fn with_number(n: u32) -> Option<Self> {
232 if n < u32::MAX { Some(Self(n)) } else { None }
233 }
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))]
250pub struct JumpTable(u32);
251entity_impl!(JumpTable, "jt");
252
253impl JumpTable {
254 /// Create a new jump table reference from its number.
255 ///
256 /// This method is for use by the parser.
257 pub fn with_number(n: u32) -> Option<Self> {
258 if n < u32::MAX { Some(Self(n)) } else { None }
259 }
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))]
279pub struct FuncRef(u32);
280entity_impl!(FuncRef, "fn");
281
282impl FuncRef {
283 /// Create a new external function reference from its number.
284 ///
285 /// This method is for use by the parser.
286 pub fn with_number(n: u32) -> Option<Self> {
287 if n < u32::MAX { Some(Self(n)) } else { None }
288 }
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))]
294pub struct UserExternalNameRef(u32);
295entity_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))]
313pub struct SigRef(u32);
314entity_impl!(SigRef, "sig");
315
316impl SigRef {
317 /// Create a new function signature reference from its number.
318 ///
319 /// This method is for use by the parser.
320 pub fn with_number(n: u32) -> Option<Self> {
321 if n < u32::MAX { Some(Self(n)) } else { None }
322 }
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))]
336pub struct ExceptionTag(u32);
337entity_impl!(ExceptionTag, "tag");
338
339impl ExceptionTag {
340 /// Create a new exception tag from its arbitrary index.
341 ///
342 /// This method is for use by the parser.
343 pub fn with_number(n: u32) -> Option<Self> {
344 if n < u32::MAX { Some(Self(n)) } else { None }
345 }
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))]
354pub struct ExceptionTable(u32);
355entity_impl!(ExceptionTable, "extable");
356
357impl ExceptionTable {
358 /// Create a new exception table reference from its number.
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 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))]
369pub 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
402impl fmt::Display for AnyEntity {
403 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
404 match *self {
405 Self::Function => write!(f, "function"),
406 Self::Block(r) => r.fmt(f),
407 Self::Inst(r) => r.fmt(f),
408 Self::Value(r) => r.fmt(f),
409 Self::StackSlot(r) => r.fmt(f),
410 Self::DynamicStackSlot(r) => r.fmt(f),
411 Self::DynamicType(r) => r.fmt(f),
412 Self::GlobalValue(r) => r.fmt(f),
413 Self::JumpTable(r) => r.fmt(f),
414 Self::Constant(r) => r.fmt(f),
415 Self::FuncRef(r) => r.fmt(f),
416 Self::SigRef(r) => r.fmt(f),
417 Self::ExceptionTable(r) => r.fmt(f),
418 Self::AliasRegion(r) => r.fmt(f),
419 Self::StackLimit => write!(f, "stack_limit"),
420 }
421 }
422}
423
424impl fmt::Debug for AnyEntity {
425 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
426 (self as &dyn fmt::Display).fmt(f)
427 }
428}
429
430impl From<Block> for AnyEntity {
431 fn from(r: Block) -> Self {
432 Self::Block(r)
433 }
434}
435
436impl From<Inst> for AnyEntity {
437 fn from(r: Inst) -> Self {
438 Self::Inst(r)
439 }
440}
441
442impl From<Value> for AnyEntity {
443 fn from(r: Value) -> Self {
444 Self::Value(r)
445 }
446}
447
448impl From<StackSlot> for AnyEntity {
449 fn from(r: StackSlot) -> Self {
450 Self::StackSlot(r)
451 }
452}
453
454impl From<DynamicStackSlot> for AnyEntity {
455 fn from(r: DynamicStackSlot) -> Self {
456 Self::DynamicStackSlot(r)
457 }
458}
459
460impl From<DynamicType> for AnyEntity {
461 fn from(r: DynamicType) -> Self {
462 Self::DynamicType(r)
463 }
464}
465
466impl From<GlobalValue> for AnyEntity {
467 fn from(r: GlobalValue) -> Self {
468 Self::GlobalValue(r)
469 }
470}
471
472impl From<JumpTable> for AnyEntity {
473 fn from(r: JumpTable) -> Self {
474 Self::JumpTable(r)
475 }
476}
477
478impl From<Constant> for AnyEntity {
479 fn from(r: Constant) -> Self {
480 Self::Constant(r)
481 }
482}
483
484impl From<FuncRef> for AnyEntity {
485 fn from(r: FuncRef) -> Self {
486 Self::FuncRef(r)
487 }
488}
489
490impl From<SigRef> for AnyEntity {
491 fn from(r: SigRef) -> Self {
492 Self::SigRef(r)
493 }
494}
495
496impl From<ExceptionTable> for AnyEntity {
497 fn from(r: ExceptionTable) -> Self {
498 Self::ExceptionTable(r)
499 }
500}
501
502impl From<AliasRegion> for AnyEntity {
503 fn from(r: AliasRegion) -> Self {
504 Self::AliasRegion(r)
505 }
506}
507
508#[cfg(test)]
509mod 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}