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 
22 use crate::entity::entity_impl;
23 use core::fmt;
24 use core::u32;
25 #[cfg(feature = "enable-serde")]
26 use 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))]
37 pub struct Block(u32);
38 entity_impl!(Block, "block");
39 
40 impl 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))]
67 pub struct Value(u32);
68 entity_impl!(Value, "v");
69 
70 impl 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))]
98 pub struct Inst(u32);
99 entity_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))]
119 pub struct StackSlot(u32);
120 entity_impl!(StackSlot, "ss");
121 
122 impl 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))]
134 pub struct DynamicStackSlot(u32);
135 entity_impl!(DynamicStackSlot, "dss");
136 
137 impl 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))]
149 pub struct DynamicType(u32);
150 entity_impl!(DynamicType, "dt");
151 
152 impl 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))]
179 pub struct GlobalValue(u32);
180 entity_impl!(GlobalValue, "gv");
181 
182 impl 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))]
198 pub struct MemoryType(u32);
199 entity_impl!(MemoryType, "mt");
200 
201 impl 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))]
220 pub struct Constant(u32);
221 entity_impl!(Constant, "const");
222 
223 impl 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))]
242 pub struct Immediate(u32);
243 entity_impl!(Immediate, "imm");
244 
245 impl 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))]
268 pub struct JumpTable(u32);
269 entity_impl!(JumpTable, "jt");
270 
271 impl 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))]
297 pub struct FuncRef(u32);
298 entity_impl!(FuncRef, "fn");
299 
300 impl 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))]
312 pub struct UserExternalNameRef(u32);
313 entity_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))]
331 pub struct SigRef(u32);
332 entity_impl!(SigRef, "sig");
333 
334 impl 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))]
354 pub struct ExceptionTag(u32);
355 entity_impl!(ExceptionTag, "tag");
356 
357 impl 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))]
372 pub struct ExceptionTable(u32);
373 entity_impl!(ExceptionTable, "extable");
374 
375 impl 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))]
387 pub 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 
420 impl 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 
442 impl 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 
448 impl From<Block> for AnyEntity {
449     fn from(r: Block) -> Self {
450         Self::Block(r)
451     }
452 }
453 
454 impl From<Inst> for AnyEntity {
455     fn from(r: Inst) -> Self {
456         Self::Inst(r)
457     }
458 }
459 
460 impl From<Value> for AnyEntity {
461     fn from(r: Value) -> Self {
462         Self::Value(r)
463     }
464 }
465 
466 impl From<StackSlot> for AnyEntity {
467     fn from(r: StackSlot) -> Self {
468         Self::StackSlot(r)
469     }
470 }
471 
472 impl From<DynamicStackSlot> for AnyEntity {
473     fn from(r: DynamicStackSlot) -> Self {
474         Self::DynamicStackSlot(r)
475     }
476 }
477 
478 impl From<DynamicType> for AnyEntity {
479     fn from(r: DynamicType) -> Self {
480         Self::DynamicType(r)
481     }
482 }
483 
484 impl From<GlobalValue> for AnyEntity {
485     fn from(r: GlobalValue) -> Self {
486         Self::GlobalValue(r)
487     }
488 }
489 
490 impl From<MemoryType> for AnyEntity {
491     fn from(r: MemoryType) -> Self {
492         Self::MemoryType(r)
493     }
494 }
495 
496 impl From<JumpTable> for AnyEntity {
497     fn from(r: JumpTable) -> Self {
498         Self::JumpTable(r)
499     }
500 }
501 
502 impl From<Constant> for AnyEntity {
503     fn from(r: Constant) -> Self {
504         Self::Constant(r)
505     }
506 }
507 
508 impl From<FuncRef> for AnyEntity {
509     fn from(r: FuncRef) -> Self {
510         Self::FuncRef(r)
511     }
512 }
513 
514 impl From<SigRef> for AnyEntity {
515     fn from(r: SigRef) -> Self {
516         Self::SigRef(r)
517     }
518 }
519 
520 impl From<ExceptionTable> for AnyEntity {
521     fn from(r: ExceptionTable) -> Self {
522         Self::ExceptionTable(r)
523     }
524 }
525 
526 #[cfg(test)]
527 mod 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 }
565