Path: blob/main/cranelift/codegen/src/ir/entities.rs
3068 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///60/// Any `InstBuilder` instruction that has an output will also return a `Value`.61///62/// While the order is stable, it is arbitrary.63#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]64#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]65pub struct Value(u32);66entity_impl!(Value, "v");6768impl Value {69/// Create a value from its number representation.70/// This is the number in the `vNN` notation.71///72/// This method is for use by the parser.73pub fn with_number(n: u32) -> Option<Self> {74if n < u32::MAX / 2 {75Some(Self(n))76} else {77None78}79}80}8182/// An opaque reference to an instruction in a [`Function`](super::Function).83///84/// Most usage of `Inst` is internal. `Inst`ructions are returned by85/// [`InstBuilder`](super::InstBuilder) instructions that do not return a86/// [`Value`], such as control flow and trap instructions, as well as instructions that return a87/// variable (potentially zero!) number of values, like call or call-indirect instructions. To get88/// the `Value` of such instructions, use [`inst_results`](super::DataFlowGraph::inst_results) or89/// its analogue in `cranelift_frontend::FuncBuilder`.90///91/// [inst_comment]: https://github.com/bjorn3/rustc_codegen_cranelift/blob/0f8814fd6da3d436a90549d4bb19b94034f2b19c/src/pretty_clif.rs92///93/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order.94#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]95#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]96pub struct Inst(u32);97entity_impl!(Inst, "inst");9899/// An opaque reference to a stack slot.100///101/// Stack slots represent an address on the102/// [call stack](https://en.wikipedia.org/wiki/Call_stack).103///104/// `StackSlot`s can be created with105/// [`FunctionBuilder::create_sized_stack_slot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_sized_stack_slot)106/// or107/// [`FunctionBuilder::create_dynamic_stack_slot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_dynamic_stack_slot).108///109/// `StackSlot`s are most often used with110/// [`stack_addr`](super::InstBuilder::stack_addr),111/// [`stack_load`](super::InstBuilder::stack_load), and112/// [`stack_store`](super::InstBuilder::stack_store).113///114/// While the order is stable, it is arbitrary and does not necessarily resemble the stack order.115#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]116#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]117pub struct StackSlot(u32);118entity_impl!(StackSlot, "ss");119120impl StackSlot {121/// Create a new stack slot reference from its number.122///123/// This method is for use by the parser.124pub fn with_number(n: u32) -> Option<Self> {125if n < u32::MAX { Some(Self(n)) } else { None }126}127}128129/// An opaque reference to a dynamic stack slot.130#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]131#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]132pub struct DynamicStackSlot(u32);133entity_impl!(DynamicStackSlot, "dss");134135impl DynamicStackSlot {136/// Create a new stack slot reference from its number.137///138/// This method is for use by the parser.139pub fn with_number(n: u32) -> Option<Self> {140if n < u32::MAX { Some(Self(n)) } else { None }141}142}143144/// An opaque reference to a dynamic type.145#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]146#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]147pub struct DynamicType(u32);148entity_impl!(DynamicType, "dt");149150impl DynamicType {151/// Create a new dynamic type reference from its number.152///153/// This method is for use by the parser.154pub fn with_number(n: u32) -> Option<Self> {155if n < u32::MAX { Some(Self(n)) } else { None }156}157}158159/// An opaque reference to a global value.160///161/// A `GlobalValue` is a [`Value`] that will be live across the entire162/// function lifetime. It can be preloaded from other global values.163///164/// You can create a `GlobalValue` in the following ways:165///166/// - When compiling to native code, you can use it for objects in static memory with167/// [`Module::declare_data_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_data_in_func).168/// - For any compilation target, it can be registered with169/// [`FunctionBuilder::create_global_value`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_global_value).170///171/// `GlobalValue`s can be retrieved with172/// [`InstBuilder:global_value`](super::InstBuilder::global_value).173///174/// While the order is stable, it is arbitrary.175#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]176#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]177pub struct GlobalValue(u32);178entity_impl!(GlobalValue, "gv");179180impl GlobalValue {181/// Create a new global value reference from its number.182///183/// This method is for use by the parser.184pub fn with_number(n: u32) -> Option<Self> {185if n < u32::MAX { Some(Self(n)) } else { None }186}187}188189/// An opaque reference to a memory type.190///191/// A `MemoryType` is a descriptor of a struct layout in memory, with192/// types and proof-carrying-code facts optionally attached to the193/// fields.194#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]195#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]196pub struct MemoryType(u32);197entity_impl!(MemoryType, "mt");198199impl MemoryType {200/// Create a new memory type reference from its number.201///202/// This method is for use by the parser.203pub fn with_number(n: u32) -> Option<Self> {204if n < u32::MAX { Some(Self(n)) } else { None }205}206}207208/// An opaque reference to a constant.209///210/// You can store [`ConstantData`](super::ConstantData) in a211/// [`ConstantPool`](super::ConstantPool) for efficient storage and retrieval.212/// See [`ConstantPool::insert`](super::ConstantPool::insert).213///214/// While the order is stable, it is arbitrary and does not necessarily resemble the order in which215/// the constants are written in the constant pool.216#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]217#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]218pub struct Constant(u32);219entity_impl!(Constant, "const");220221impl Constant {222/// Create a const reference from its number.223///224/// This method is for use by the parser.225pub fn with_number(n: u32) -> Option<Self> {226if n < u32::MAX { Some(Self(n)) } else { None }227}228}229230/// An opaque reference to an immediate.231///232/// Some immediates (e.g. SIMD shuffle masks) are too large to store in the233/// [`InstructionData`](super::instructions::InstructionData) struct and therefore must be234/// tracked separately in [`DataFlowGraph::immediates`](super::dfg::DataFlowGraph). `Immediate`235/// provides a way to reference values stored there.236///237/// While the order is stable, it is arbitrary.238#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]239#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]240pub struct Immediate(u32);241entity_impl!(Immediate, "imm");242243impl Immediate {244/// Create an immediate reference from its number.245///246/// This method is for use by the parser.247pub fn with_number(n: u32) -> Option<Self> {248if n < u32::MAX { Some(Self(n)) } else { None }249}250}251252/// An opaque reference to a [jump table](https://en.wikipedia.org/wiki/Branch_table).253///254/// `JumpTable`s are used for indirect branching and are specialized for dense,255/// 0-based jump offsets. If you want a jump table which doesn't start at 0,256/// or is not contiguous, consider using a [`Switch`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.Switch.html) instead.257///258/// `JumpTable` are used with [`br_table`](super::InstBuilder::br_table).259///260/// `JumpTable`s can be created with261/// [`create_jump_table`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_jump_table).262///263/// While the order is stable, it is arbitrary.264#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]265#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]266pub struct JumpTable(u32);267entity_impl!(JumpTable, "jt");268269impl JumpTable {270/// Create a new jump table reference from its number.271///272/// This method is for use by the parser.273pub fn with_number(n: u32) -> Option<Self> {274if n < u32::MAX { Some(Self(n)) } else { None }275}276}277278/// An opaque reference to another [`Function`](super::Function).279///280/// `FuncRef`s are used for [direct](super::InstBuilder::call) function calls281/// and by [`func_addr`](super::InstBuilder::func_addr) for use in282/// [indirect](super::InstBuilder::call_indirect) function calls.283///284/// `FuncRef`s can be created with285///286/// - [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)287/// for external functions288/// - [`Module::declare_func_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_func_in_func)289/// for functions declared elsewhere in the same native290/// [`Module`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html)291///292/// While the order is stable, it is arbitrary.293#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]294#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]295pub struct FuncRef(u32);296entity_impl!(FuncRef, "fn");297298impl FuncRef {299/// Create a new external function reference from its number.300///301/// This method is for use by the parser.302pub fn with_number(n: u32) -> Option<Self> {303if n < u32::MAX { Some(Self(n)) } else { None }304}305}306307/// A reference to an `UserExternalName`, declared with `Function::declare_imported_user_function`.308#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]309#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]310pub struct UserExternalNameRef(u32);311entity_impl!(UserExternalNameRef, "userextname");312313/// An opaque reference to a function [`Signature`](super::Signature).314///315/// `SigRef`s are used to declare a function with316/// [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)317/// as well as to make an [indirect function call](super::InstBuilder::call_indirect).318///319/// `SigRef`s can be created with320/// [`FunctionBuilder::import_signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_signature).321///322/// You can retrieve the [`Signature`](super::Signature) that was used to create a `SigRef` with323/// [`FunctionBuilder::signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.signature) or324/// [`func.dfg.signatures`](super::dfg::DataFlowGraph::signatures).325///326/// While the order is stable, it is arbitrary.327#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]328#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]329pub struct SigRef(u32);330entity_impl!(SigRef, "sig");331332impl SigRef {333/// Create a new function signature reference from its number.334///335/// This method is for use by the parser.336pub fn with_number(n: u32) -> Option<Self> {337if n < u32::MAX { Some(Self(n)) } else { None }338}339}340341/// An opaque exception tag.342///343/// Exception tags are used to denote the identity of an exception for344/// matching by catch-handlers in exception tables.345///346/// The index space is arbitrary and is given meaning only by the347/// embedder of Cranelift. Cranelift will carry through these tags348/// from exception tables to the handler metadata produced as output349/// (for use by the embedder's unwinder).350#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]351#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]352pub struct ExceptionTag(u32);353entity_impl!(ExceptionTag, "tag");354355impl ExceptionTag {356/// Create a new exception tag from its arbitrary index.357///358/// This method is for use by the parser.359pub fn with_number(n: u32) -> Option<Self> {360if n < u32::MAX { Some(Self(n)) } else { None }361}362}363364/// An opaque reference to an exception table.365///366/// `ExceptionTable`s are used for describing exception catch handlers on367/// `try_call` and `try_call_indirect` instructions.368#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]369#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]370pub struct ExceptionTable(u32);371entity_impl!(ExceptionTable, "extable");372373impl ExceptionTable {374/// Create a new exception table reference from its number.375///376/// This method is for use by the parser.377pub fn with_number(n: u32) -> Option<Self> {378if n < u32::MAX { Some(Self(n)) } else { None }379}380}381382/// An opaque reference to any of the entities defined in this module that can appear in CLIF IR.383#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]384#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]385pub enum AnyEntity {386/// The whole function.387Function,388/// a basic block.389Block(Block),390/// An instruction.391Inst(Inst),392/// An SSA value.393Value(Value),394/// A stack slot.395StackSlot(StackSlot),396/// A dynamic stack slot.397DynamicStackSlot(DynamicStackSlot),398/// A dynamic type399DynamicType(DynamicType),400/// A Global value.401GlobalValue(GlobalValue),402/// A memory type.403MemoryType(MemoryType),404/// A jump table.405JumpTable(JumpTable),406/// A constant.407Constant(Constant),408/// An external function.409FuncRef(FuncRef),410/// A function call signature.411SigRef(SigRef),412/// An exception table.413ExceptionTable(ExceptionTable),414/// A function's stack limit415StackLimit,416}417418impl fmt::Display for AnyEntity {419fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {420match *self {421Self::Function => write!(f, "function"),422Self::Block(r) => r.fmt(f),423Self::Inst(r) => r.fmt(f),424Self::Value(r) => r.fmt(f),425Self::StackSlot(r) => r.fmt(f),426Self::DynamicStackSlot(r) => r.fmt(f),427Self::DynamicType(r) => r.fmt(f),428Self::GlobalValue(r) => r.fmt(f),429Self::MemoryType(r) => r.fmt(f),430Self::JumpTable(r) => r.fmt(f),431Self::Constant(r) => r.fmt(f),432Self::FuncRef(r) => r.fmt(f),433Self::SigRef(r) => r.fmt(f),434Self::ExceptionTable(r) => r.fmt(f),435Self::StackLimit => write!(f, "stack_limit"),436}437}438}439440impl fmt::Debug for AnyEntity {441fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {442(self as &dyn fmt::Display).fmt(f)443}444}445446impl From<Block> for AnyEntity {447fn from(r: Block) -> Self {448Self::Block(r)449}450}451452impl From<Inst> for AnyEntity {453fn from(r: Inst) -> Self {454Self::Inst(r)455}456}457458impl From<Value> for AnyEntity {459fn from(r: Value) -> Self {460Self::Value(r)461}462}463464impl From<StackSlot> for AnyEntity {465fn from(r: StackSlot) -> Self {466Self::StackSlot(r)467}468}469470impl From<DynamicStackSlot> for AnyEntity {471fn from(r: DynamicStackSlot) -> Self {472Self::DynamicStackSlot(r)473}474}475476impl From<DynamicType> for AnyEntity {477fn from(r: DynamicType) -> Self {478Self::DynamicType(r)479}480}481482impl From<GlobalValue> for AnyEntity {483fn from(r: GlobalValue) -> Self {484Self::GlobalValue(r)485}486}487488impl From<MemoryType> for AnyEntity {489fn from(r: MemoryType) -> Self {490Self::MemoryType(r)491}492}493494impl From<JumpTable> for AnyEntity {495fn from(r: JumpTable) -> Self {496Self::JumpTable(r)497}498}499500impl From<Constant> for AnyEntity {501fn from(r: Constant) -> Self {502Self::Constant(r)503}504}505506impl From<FuncRef> for AnyEntity {507fn from(r: FuncRef) -> Self {508Self::FuncRef(r)509}510}511512impl From<SigRef> for AnyEntity {513fn from(r: SigRef) -> Self {514Self::SigRef(r)515}516}517518impl From<ExceptionTable> for AnyEntity {519fn from(r: ExceptionTable) -> Self {520Self::ExceptionTable(r)521}522}523524#[cfg(test)]525mod tests {526use super::*;527use alloc::string::ToString;528529#[test]530fn value_with_number() {531assert_eq!(Value::with_number(0).unwrap().to_string(), "v0");532assert_eq!(Value::with_number(1).unwrap().to_string(), "v1");533534assert_eq!(Value::with_number(u32::MAX / 2), None);535assert!(Value::with_number(u32::MAX / 2 - 1).is_some());536}537538#[test]539fn memory() {540use crate::packed_option::PackedOption;541use core::mem;542// This is the whole point of `PackedOption`.543assert_eq!(544mem::size_of::<Value>(),545mem::size_of::<PackedOption<Value>>()546);547}548549#[test]550fn memory_option() {551use core::mem;552// PackedOption is used because Option<EntityRef> is twice as large553// as EntityRef. If this ever fails to be the case, this test will fail.554assert_eq!(mem::size_of::<Value>() * 2, mem::size_of::<Option<Value>>());555}556557#[test]558fn constant_with_number() {559assert_eq!(Constant::with_number(0).unwrap().to_string(), "const0");560assert_eq!(Constant::with_number(1).unwrap().to_string(), "const1");561}562}563564565