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