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