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