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