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