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.
with_number(n: u32) -> Option<Self>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.
with_number(n: u32) -> Option<Self>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.
with_number(n: u32) -> Option<Self>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.
with_number(n: u32) -> Option<Self>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.
with_number(n: u32) -> Option<Self>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.
with_number(n: u32) -> Option<Self>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 constant.
191 ///
192 /// You can store [`ConstantData`](super::ConstantData) in a
193 /// [`ConstantPool`](super::ConstantPool) for efficient storage and retrieval.
194 /// See [`ConstantPool::insert`](super::ConstantPool::insert).
195 ///
196 /// While the order is stable, it is arbitrary and does not necessarily resemble the order in which
197 /// the constants are written in the constant pool.
198 #[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
199 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
200 pub struct Constant(u32);
201 entity_impl!(Constant, "const");
202 
203 impl Constant {
204     /// Create a const reference from its number.
205     ///
206     /// This method is for use by the parser.
with_number(n: u32) -> Option<Self>207     pub fn with_number(n: u32) -> Option<Self> {
208         if n < u32::MAX { Some(Self(n)) } else { None }
209     }
210 }
211 
212 /// An opaque reference to an immediate.
213 ///
214 /// Some immediates (e.g. SIMD shuffle masks) are too large to store in the
215 /// [`InstructionData`](super::instructions::InstructionData) struct and therefore must be
216 /// tracked separately in [`DataFlowGraph::immediates`](super::dfg::DataFlowGraph). `Immediate`
217 /// provides a way to reference values stored there.
218 ///
219 /// While the order is stable, it is arbitrary.
220 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
221 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
222 pub struct Immediate(u32);
223 entity_impl!(Immediate, "imm");
224 
225 impl Immediate {
226     /// Create an immediate reference from its number.
227     ///
228     /// This method is for use by the parser.
with_number(n: u32) -> Option<Self>229     pub fn with_number(n: u32) -> Option<Self> {
230         if n < u32::MAX { Some(Self(n)) } else { None }
231     }
232 }
233 
234 /// An opaque reference to a [jump table](https://en.wikipedia.org/wiki/Branch_table).
235 ///
236 /// `JumpTable`s are used for indirect branching and are specialized for dense,
237 /// 0-based jump offsets. If you want a jump table which doesn't start at 0,
238 /// or is not contiguous, consider using a [`Switch`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.Switch.html) instead.
239 ///
240 /// `JumpTable` are used with [`br_table`](super::InstBuilder::br_table).
241 ///
242 /// `JumpTable`s can be created with
243 /// [`create_jump_table`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_jump_table).
244 ///
245 /// While the order is stable, it is arbitrary.
246 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
247 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
248 pub struct JumpTable(u32);
249 entity_impl!(JumpTable, "jt");
250 
251 impl JumpTable {
252     /// Create a new jump table reference from its number.
253     ///
254     /// This method is for use by the parser.
with_number(n: u32) -> Option<Self>255     pub fn with_number(n: u32) -> Option<Self> {
256         if n < u32::MAX { Some(Self(n)) } else { None }
257     }
258 }
259 
260 /// An opaque reference to another [`Function`](super::Function).
261 ///
262 /// `FuncRef`s are used for [direct](super::InstBuilder::call) function calls
263 /// and by [`func_addr`](super::InstBuilder::func_addr) for use in
264 /// [indirect](super::InstBuilder::call_indirect) function calls.
265 ///
266 /// `FuncRef`s can be created with
267 ///
268 /// - [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
269 ///   for external functions
270 /// - [`Module::declare_func_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_func_in_func)
271 ///   for functions declared elsewhere in the same native
272 ///   [`Module`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html)
273 ///
274 /// While the order is stable, it is arbitrary.
275 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
276 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
277 pub struct FuncRef(u32);
278 entity_impl!(FuncRef, "fn");
279 
280 impl FuncRef {
281     /// Create a new external function reference from its number.
282     ///
283     /// This method is for use by the parser.
with_number(n: u32) -> Option<Self>284     pub fn with_number(n: u32) -> Option<Self> {
285         if n < u32::MAX { Some(Self(n)) } else { None }
286     }
287 }
288 
289 /// A reference to an `UserExternalName`, declared with `Function::declare_imported_user_function`.
290 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
291 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
292 pub struct UserExternalNameRef(u32);
293 entity_impl!(UserExternalNameRef, "userextname");
294 
295 /// An opaque reference to a function [`Signature`](super::Signature).
296 ///
297 /// `SigRef`s are used to declare a function with
298 /// [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
299 /// as well as to make an [indirect function call](super::InstBuilder::call_indirect).
300 ///
301 /// `SigRef`s can be created with
302 /// [`FunctionBuilder::import_signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_signature).
303 ///
304 /// You can retrieve the [`Signature`](super::Signature) that was used to create a `SigRef` with
305 /// [`FunctionBuilder::signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.signature) or
306 /// [`func.dfg.signatures`](super::dfg::DataFlowGraph::signatures).
307 ///
308 /// While the order is stable, it is arbitrary.
309 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
310 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
311 pub struct SigRef(u32);
312 entity_impl!(SigRef, "sig");
313 
314 impl SigRef {
315     /// Create a new function signature reference from its number.
316     ///
317     /// This method is for use by the parser.
with_number(n: u32) -> Option<Self>318     pub fn with_number(n: u32) -> Option<Self> {
319         if n < u32::MAX { Some(Self(n)) } else { None }
320     }
321 }
322 
323 /// An opaque exception tag.
324 ///
325 /// Exception tags are used to denote the identity of an exception for
326 /// matching by catch-handlers in exception tables.
327 ///
328 /// The index space is arbitrary and is given meaning only by the
329 /// embedder of Cranelift. Cranelift will carry through these tags
330 /// from exception tables to the handler metadata produced as output
331 /// (for use by the embedder's unwinder).
332 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
333 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
334 pub struct ExceptionTag(u32);
335 entity_impl!(ExceptionTag, "tag");
336 
337 impl ExceptionTag {
338     /// Create a new exception tag from its arbitrary index.
339     ///
340     /// This method is for use by the parser.
with_number(n: u32) -> Option<Self>341     pub fn with_number(n: u32) -> Option<Self> {
342         if n < u32::MAX { Some(Self(n)) } else { None }
343     }
344 }
345 
346 /// An opaque reference to an exception table.
347 ///
348 /// `ExceptionTable`s are used for describing exception catch handlers on
349 /// `try_call` and `try_call_indirect` instructions.
350 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
351 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
352 pub struct ExceptionTable(u32);
353 entity_impl!(ExceptionTable, "extable");
354 
355 impl ExceptionTable {
356     /// Create a new exception table reference from its number.
357     ///
358     /// This method is for use by the parser.
with_number(n: u32) -> Option<Self>359     pub fn with_number(n: u32) -> Option<Self> {
360         if n < u32::MAX { Some(Self(n)) } else { None }
361     }
362 }
363 
364 /// An opaque reference to any of the entities defined in this module that can appear in CLIF IR.
365 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
366 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
367 pub enum AnyEntity {
368     /// The whole function.
369     Function,
370     /// a basic block.
371     Block(Block),
372     /// An instruction.
373     Inst(Inst),
374     /// An SSA value.
375     Value(Value),
376     /// A stack slot.
377     StackSlot(StackSlot),
378     /// A dynamic stack slot.
379     DynamicStackSlot(DynamicStackSlot),
380     /// A dynamic type
381     DynamicType(DynamicType),
382     /// A Global value.
383     GlobalValue(GlobalValue),
384     /// A jump table.
385     JumpTable(JumpTable),
386     /// A constant.
387     Constant(Constant),
388     /// An external function.
389     FuncRef(FuncRef),
390     /// A function call signature.
391     SigRef(SigRef),
392     /// An exception table.
393     ExceptionTable(ExceptionTable),
394     /// A function's stack limit
395     StackLimit,
396 }
397 
398 impl fmt::Display for AnyEntity {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result399     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400         match *self {
401             Self::Function => write!(f, "function"),
402             Self::Block(r) => r.fmt(f),
403             Self::Inst(r) => r.fmt(f),
404             Self::Value(r) => r.fmt(f),
405             Self::StackSlot(r) => r.fmt(f),
406             Self::DynamicStackSlot(r) => r.fmt(f),
407             Self::DynamicType(r) => r.fmt(f),
408             Self::GlobalValue(r) => r.fmt(f),
409             Self::JumpTable(r) => r.fmt(f),
410             Self::Constant(r) => r.fmt(f),
411             Self::FuncRef(r) => r.fmt(f),
412             Self::SigRef(r) => r.fmt(f),
413             Self::ExceptionTable(r) => r.fmt(f),
414             Self::StackLimit => write!(f, "stack_limit"),
415         }
416     }
417 }
418 
419 impl fmt::Debug for AnyEntity {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result420     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
421         (self as &dyn fmt::Display).fmt(f)
422     }
423 }
424 
425 impl From<Block> for AnyEntity {
from(r: Block) -> Self426     fn from(r: Block) -> Self {
427         Self::Block(r)
428     }
429 }
430 
431 impl From<Inst> for AnyEntity {
from(r: Inst) -> Self432     fn from(r: Inst) -> Self {
433         Self::Inst(r)
434     }
435 }
436 
437 impl From<Value> for AnyEntity {
from(r: Value) -> Self438     fn from(r: Value) -> Self {
439         Self::Value(r)
440     }
441 }
442 
443 impl From<StackSlot> for AnyEntity {
from(r: StackSlot) -> Self444     fn from(r: StackSlot) -> Self {
445         Self::StackSlot(r)
446     }
447 }
448 
449 impl From<DynamicStackSlot> for AnyEntity {
from(r: DynamicStackSlot) -> Self450     fn from(r: DynamicStackSlot) -> Self {
451         Self::DynamicStackSlot(r)
452     }
453 }
454 
455 impl From<DynamicType> for AnyEntity {
from(r: DynamicType) -> Self456     fn from(r: DynamicType) -> Self {
457         Self::DynamicType(r)
458     }
459 }
460 
461 impl From<GlobalValue> for AnyEntity {
from(r: GlobalValue) -> Self462     fn from(r: GlobalValue) -> Self {
463         Self::GlobalValue(r)
464     }
465 }
466 
467 impl From<JumpTable> for AnyEntity {
from(r: JumpTable) -> Self468     fn from(r: JumpTable) -> Self {
469         Self::JumpTable(r)
470     }
471 }
472 
473 impl From<Constant> for AnyEntity {
from(r: Constant) -> Self474     fn from(r: Constant) -> Self {
475         Self::Constant(r)
476     }
477 }
478 
479 impl From<FuncRef> for AnyEntity {
from(r: FuncRef) -> Self480     fn from(r: FuncRef) -> Self {
481         Self::FuncRef(r)
482     }
483 }
484 
485 impl From<SigRef> for AnyEntity {
from(r: SigRef) -> Self486     fn from(r: SigRef) -> Self {
487         Self::SigRef(r)
488     }
489 }
490 
491 impl From<ExceptionTable> for AnyEntity {
from(r: ExceptionTable) -> Self492     fn from(r: ExceptionTable) -> Self {
493         Self::ExceptionTable(r)
494     }
495 }
496 
497 #[cfg(test)]
498 mod tests {
499     use super::*;
500     use alloc::string::ToString;
501 
502     #[test]
value_with_number()503     fn value_with_number() {
504         assert_eq!(Value::with_number(0).unwrap().to_string(), "v0");
505         assert_eq!(Value::with_number(1).unwrap().to_string(), "v1");
506 
507         assert_eq!(Value::with_number(u32::MAX / 2), None);
508         assert!(Value::with_number(u32::MAX / 2 - 1).is_some());
509     }
510 
511     #[test]
memory()512     fn memory() {
513         use crate::packed_option::PackedOption;
514         use core::mem;
515         // This is the whole point of `PackedOption`.
516         assert_eq!(
517             mem::size_of::<Value>(),
518             mem::size_of::<PackedOption<Value>>()
519         );
520     }
521 
522     #[test]
memory_option()523     fn memory_option() {
524         use core::mem;
525         // PackedOption is used because Option<EntityRef> is twice as large
526         // as EntityRef. If this ever fails to be the case, this test will fail.
527         assert_eq!(mem::size_of::<Value>() * 2, mem::size_of::<Option<Value>>());
528     }
529 
530     #[test]
constant_with_number()531     fn constant_with_number() {
532         assert_eq!(Constant::with_number(0).unwrap().to_string(), "const0");
533         assert_eq!(Constant::with_number(1).unwrap().to_string(), "const1");
534     }
535 }
536