Path: blob/main/cranelift/codegen/src/ir/entities.rs
1693 views
//! Cranelift IR entity references.1//!2//! Instructions in Cranelift IR need to reference other entities in the function. This can be other3//! parts of the function like basic blocks or stack slots, or it can be external entities4//! that are declared in the function preamble in the text format.5//!6//! These entity references in instruction operands are not implemented as Rust references both7//! because Rust's ownership and mutability rules make it difficult, and because 64-bit pointers8//! take up a lot of space, and we want a compact in-memory representation. Instead, entity9//! references are structs wrapping a `u32` index into a table in the `Function` main data10//! structure. There is a separate index type for each entity type, so we don't lose type safety.11//!12//! The `entities` module defines public types for the entity references along with constants13//! representing an invalid reference. We prefer to use `Option<EntityRef>` whenever possible, but14//! unfortunately that type is twice as large as the 32-bit index type on its own. Thus, compact15//! data structures use the `PackedOption<EntityRef>` representation, while function arguments and16//! return values prefer the more Rust-like `Option<EntityRef>` variant.17//!18//! The entity references all implement the `Display` trait in a way that matches the textual IR19//! format.2021use crate::entity::entity_impl;22use core::fmt;23use core::u32;24#[cfg(feature = "enable-serde")]25use serde_derive::{Deserialize, Serialize};2627/// An opaque reference to a [basic block](https://en.wikipedia.org/wiki/Basic_block) in a28/// [`Function`](super::function::Function).29///30/// You can get a `Block` using31/// [`FunctionBuilder::create_block`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_block)32///33/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order.34#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]35#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]36pub struct Block(u32);37entity_impl!(Block, "block");3839impl Block {40/// Create a new block reference from its number. This corresponds to the `blockNN` representation.41///42/// This method is for use by the parser.43pub fn with_number(n: u32) -> Option<Self> {44if n < u32::MAX { Some(Self(n)) } else { None }45}46}4748/// An opaque reference to an SSA value.49///50/// You can get a constant `Value` from the following51/// [`InstBuilder`](super::InstBuilder) instructions:52///53/// - [`iconst`](super::InstBuilder::iconst) for integer constants54/// - [`f16const`](super::InstBuilder::f16const) for 16-bit float constants55/// - [`f32const`](super::InstBuilder::f32const) for 32-bit float constants56/// - [`f64const`](super::InstBuilder::f64const) for 64-bit float constants57/// - [`f128const`](super::InstBuilder::f128const) for 128-bit float constants58/// - [`vconst`](super::InstBuilder::vconst) for vector constants59/// - [`null`](super::InstBuilder::null) for null reference constants60///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))]66pub struct Value(u32);67entity_impl!(Value, "v");6869impl 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.74pub fn with_number(n: u32) -> Option<Self> {75if n < u32::MAX / 2 {76Some(Self(n))77} else {78None79}80}81}8283/// An opaque reference to an instruction in a [`Function`](super::Function).84///85/// Most usage of `Inst` is internal. `Inst`ructions are returned by86/// [`InstBuilder`](super::InstBuilder) instructions that do not return a87/// [`Value`], such as control flow and trap instructions, as well as instructions that return a88/// variable (potentially zero!) number of values, like call or call-indirect instructions. To get89/// the `Value` of such instructions, use [`inst_results`](super::DataFlowGraph::inst_results) or90/// its analogue in `cranelift_frontend::FuncBuilder`.91///92/// [inst_comment]: https://github.com/bjorn3/rustc_codegen_cranelift/blob/0f8814fd6da3d436a90549d4bb19b94034f2b19c/src/pretty_clif.rs93///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))]97pub struct Inst(u32);98entity_impl!(Inst, "inst");99100/// An opaque reference to a stack slot.101///102/// Stack slots represent an address on the103/// [call stack](https://en.wikipedia.org/wiki/Call_stack).104///105/// `StackSlot`s can be created with106/// [`FunctionBuilder::create_sized_stack_slot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_sized_stack_slot)107/// or108/// [`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 with111/// [`stack_addr`](super::InstBuilder::stack_addr),112/// [`stack_load`](super::InstBuilder::stack_load), and113/// [`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))]118pub struct StackSlot(u32);119entity_impl!(StackSlot, "ss");120121impl StackSlot {122/// Create a new stack slot reference from its number.123///124/// This method is for use by the parser.125pub fn with_number(n: u32) -> Option<Self> {126if n < u32::MAX { Some(Self(n)) } else { None }127}128}129130/// 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))]133pub struct DynamicStackSlot(u32);134entity_impl!(DynamicStackSlot, "dss");135136impl DynamicStackSlot {137/// Create a new stack slot reference from its number.138///139/// This method is for use by the parser.140pub fn with_number(n: u32) -> Option<Self> {141if n < u32::MAX { Some(Self(n)) } else { None }142}143}144145/// 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))]148pub struct DynamicType(u32);149entity_impl!(DynamicType, "dt");150151impl DynamicType {152/// Create a new dynamic type reference from its number.153///154/// This method is for use by the parser.155pub fn with_number(n: u32) -> Option<Self> {156if n < u32::MAX { Some(Self(n)) } else { None }157}158}159160/// An opaque reference to a global value.161///162/// A `GlobalValue` is a [`Value`] that will be live across the entire163/// 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 with168/// [`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 with170/// [`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 with173/// [`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))]178pub struct GlobalValue(u32);179entity_impl!(GlobalValue, "gv");180181impl GlobalValue {182/// Create a new global value reference from its number.183///184/// This method is for use by the parser.185pub fn with_number(n: u32) -> Option<Self> {186if n < u32::MAX { Some(Self(n)) } else { None }187}188}189190/// An opaque reference to a memory type.191///192/// A `MemoryType` is a descriptor of a struct layout in memory, with193/// types and proof-carrying-code facts optionally attached to the194/// fields.195#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]196#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]197pub struct MemoryType(u32);198entity_impl!(MemoryType, "mt");199200impl MemoryType {201/// Create a new memory type reference from its number.202///203/// This method is for use by the parser.204pub fn with_number(n: u32) -> Option<Self> {205if n < u32::MAX { Some(Self(n)) } else { None }206}207}208209/// An opaque reference to a constant.210///211/// You can store [`ConstantData`](super::ConstantData) in a212/// [`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 which216/// 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))]219pub struct Constant(u32);220entity_impl!(Constant, "const");221222impl Constant {223/// Create a const reference from its number.224///225/// This method is for use by the parser.226pub fn with_number(n: u32) -> Option<Self> {227if n < u32::MAX { Some(Self(n)) } else { None }228}229}230231/// An opaque reference to an immediate.232///233/// Some immediates (e.g. SIMD shuffle masks) are too large to store in the234/// [`InstructionData`](super::instructions::InstructionData) struct and therefore must be235/// 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))]241pub struct Immediate(u32);242entity_impl!(Immediate, "imm");243244impl Immediate {245/// Create an immediate reference from its number.246///247/// This method is for use by the parser.248pub fn with_number(n: u32) -> Option<Self> {249if n < u32::MAX { Some(Self(n)) } else { None }250}251}252253/// 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 with262/// [`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))]267pub struct JumpTable(u32);268entity_impl!(JumpTable, "jt");269270impl JumpTable {271/// Create a new jump table reference from its number.272///273/// This method is for use by the parser.274pub fn with_number(n: u32) -> Option<Self> {275if n < u32::MAX { Some(Self(n)) } else { None }276}277}278279/// An opaque reference to another [`Function`](super::Function).280///281/// `FuncRef`s are used for [direct](super::InstBuilder::call) function calls282/// and by [`func_addr`](super::InstBuilder::func_addr) for use in283/// [indirect](super::InstBuilder::call_indirect) function calls.284///285/// `FuncRef`s can be created with286///287/// - [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)288/// for external functions289/// - [`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 native291/// [`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))]296pub struct FuncRef(u32);297entity_impl!(FuncRef, "fn");298299impl FuncRef {300/// Create a new external function reference from its number.301///302/// This method is for use by the parser.303pub fn with_number(n: u32) -> Option<Self> {304if n < u32::MAX { Some(Self(n)) } else { None }305}306}307308/// 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))]311pub struct UserExternalNameRef(u32);312entity_impl!(UserExternalNameRef, "userextname");313314/// An opaque reference to a function [`Signature`](super::Signature).315///316/// `SigRef`s are used to declare a function with317/// [`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 with321/// [`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` with324/// [`FunctionBuilder::signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.signature) or325/// [`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))]330pub struct SigRef(u32);331entity_impl!(SigRef, "sig");332333impl SigRef {334/// Create a new function signature reference from its number.335///336/// This method is for use by the parser.337pub fn with_number(n: u32) -> Option<Self> {338if n < u32::MAX { Some(Self(n)) } else { None }339}340}341342/// An opaque exception tag.343///344/// Exception tags are used to denote the identity of an exception for345/// matching by catch-handlers in exception tables.346///347/// The index space is arbitrary and is given meaning only by the348/// embedder of Cranelift. Cranelift will carry through these tags349/// from exception tables to the handler metadata produced as output350/// (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))]353pub struct ExceptionTag(u32);354entity_impl!(ExceptionTag, "tag");355356impl ExceptionTag {357/// Create a new exception tag from its arbitrary index.358///359/// This method is for use by the parser.360pub fn with_number(n: u32) -> Option<Self> {361if n < u32::MAX { Some(Self(n)) } else { None }362}363}364365/// An opaque reference to an exception table.366///367/// `ExceptionTable`s are used for describing exception catch handlers on368/// `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))]371pub struct ExceptionTable(u32);372entity_impl!(ExceptionTable, "extable");373374impl ExceptionTable {375/// Create a new exception table reference from its number.376///377/// This method is for use by the parser.378pub fn with_number(n: u32) -> Option<Self> {379if n < u32::MAX { Some(Self(n)) } else { None }380}381}382383/// 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))]386pub enum AnyEntity {387/// The whole function.388Function,389/// a basic block.390Block(Block),391/// An instruction.392Inst(Inst),393/// An SSA value.394Value(Value),395/// A stack slot.396StackSlot(StackSlot),397/// A dynamic stack slot.398DynamicStackSlot(DynamicStackSlot),399/// A dynamic type400DynamicType(DynamicType),401/// A Global value.402GlobalValue(GlobalValue),403/// A memory type.404MemoryType(MemoryType),405/// A jump table.406JumpTable(JumpTable),407/// A constant.408Constant(Constant),409/// An external function.410FuncRef(FuncRef),411/// A function call signature.412SigRef(SigRef),413/// An exception table.414ExceptionTable(ExceptionTable),415/// A function's stack limit416StackLimit,417}418419impl fmt::Display for AnyEntity {420fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {421match *self {422Self::Function => write!(f, "function"),423Self::Block(r) => r.fmt(f),424Self::Inst(r) => r.fmt(f),425Self::Value(r) => r.fmt(f),426Self::StackSlot(r) => r.fmt(f),427Self::DynamicStackSlot(r) => r.fmt(f),428Self::DynamicType(r) => r.fmt(f),429Self::GlobalValue(r) => r.fmt(f),430Self::MemoryType(r) => r.fmt(f),431Self::JumpTable(r) => r.fmt(f),432Self::Constant(r) => r.fmt(f),433Self::FuncRef(r) => r.fmt(f),434Self::SigRef(r) => r.fmt(f),435Self::ExceptionTable(r) => r.fmt(f),436Self::StackLimit => write!(f, "stack_limit"),437}438}439}440441impl fmt::Debug for AnyEntity {442fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {443(self as &dyn fmt::Display).fmt(f)444}445}446447impl From<Block> for AnyEntity {448fn from(r: Block) -> Self {449Self::Block(r)450}451}452453impl From<Inst> for AnyEntity {454fn from(r: Inst) -> Self {455Self::Inst(r)456}457}458459impl From<Value> for AnyEntity {460fn from(r: Value) -> Self {461Self::Value(r)462}463}464465impl From<StackSlot> for AnyEntity {466fn from(r: StackSlot) -> Self {467Self::StackSlot(r)468}469}470471impl From<DynamicStackSlot> for AnyEntity {472fn from(r: DynamicStackSlot) -> Self {473Self::DynamicStackSlot(r)474}475}476477impl From<DynamicType> for AnyEntity {478fn from(r: DynamicType) -> Self {479Self::DynamicType(r)480}481}482483impl From<GlobalValue> for AnyEntity {484fn from(r: GlobalValue) -> Self {485Self::GlobalValue(r)486}487}488489impl From<MemoryType> for AnyEntity {490fn from(r: MemoryType) -> Self {491Self::MemoryType(r)492}493}494495impl From<JumpTable> for AnyEntity {496fn from(r: JumpTable) -> Self {497Self::JumpTable(r)498}499}500501impl From<Constant> for AnyEntity {502fn from(r: Constant) -> Self {503Self::Constant(r)504}505}506507impl From<FuncRef> for AnyEntity {508fn from(r: FuncRef) -> Self {509Self::FuncRef(r)510}511}512513impl From<SigRef> for AnyEntity {514fn from(r: SigRef) -> Self {515Self::SigRef(r)516}517}518519impl From<ExceptionTable> for AnyEntity {520fn from(r: ExceptionTable) -> Self {521Self::ExceptionTable(r)522}523}524525#[cfg(test)]526mod tests {527use super::*;528use alloc::string::ToString;529530#[test]531fn value_with_number() {532assert_eq!(Value::with_number(0).unwrap().to_string(), "v0");533assert_eq!(Value::with_number(1).unwrap().to_string(), "v1");534535assert_eq!(Value::with_number(u32::MAX / 2), None);536assert!(Value::with_number(u32::MAX / 2 - 1).is_some());537}538539#[test]540fn memory() {541use crate::packed_option::PackedOption;542use core::mem;543// This is the whole point of `PackedOption`.544assert_eq!(545mem::size_of::<Value>(),546mem::size_of::<PackedOption<Value>>()547);548}549550#[test]551fn memory_option() {552use core::mem;553// PackedOption is used because Option<EntityRef> is twice as large554// as EntityRef. If this ever fails to be the case, this test will fail.555assert_eq!(mem::size_of::<Value>() * 2, mem::size_of::<Option<Value>>());556}557558#[test]559fn constant_with_number() {560assert_eq!(Constant::with_number(0).unwrap().to_string(), "const0");561assert_eq!(Constant::with_number(1).unwrap().to_string(), "const1");562}563}564565566