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