Path: blob/main/cranelift/codegen/meta/src/cdsl/formats.rs
1693 views
use crate::cdsl::operands::OperandKind;1use std::fmt;2use std::rc::Rc;34/// An immediate field in an instruction format.5///6/// This corresponds to a single member of a variant of the `InstructionData`7/// data type.8#[derive(Debug)]9pub(crate) struct FormatField {10/// Immediate operand kind.11pub kind: OperandKind,1213/// Member name in InstructionData variant.14pub member: &'static str,15}1617/// Every instruction opcode has a corresponding instruction format which determines the number of18/// operands and their kinds. Instruction formats are identified structurally, i.e., the format of19/// an instruction is derived from the kinds of operands used in its declaration.20///21/// The instruction format stores two separate lists of operands: Immediates and values. Immediate22/// operands (including entity references) are represented as explicit members in the23/// `InstructionData` variants. The value operands are stored differently, depending on how many24/// there are. Beyond a certain point, instruction formats switch to an external value list for25/// storing value arguments. Value lists can hold an arbitrary number of values.26///27/// All instruction formats must be predefined in the meta shared/formats.rs module.28#[derive(Debug)]29pub(crate) struct InstructionFormat {30/// Instruction format name in CamelCase. This is used as a Rust variant name in both the31/// `InstructionData` and `InstructionFormat` enums.32pub name: &'static str,3334pub num_value_operands: usize,3536pub has_value_list: bool,3738pub imm_fields: Vec<FormatField>,3940pub num_block_operands: usize,4142pub num_raw_block_operands: usize,4344/// Index of the value input operand that is used to infer the controlling type variable. By45/// default, this is `0`, the first `value` operand. The index is relative to the values only,46/// ignoring immediate operands.47pub typevar_operand: Option<usize>,48}4950/// A tuple serving as a key to deduplicate InstructionFormat.51#[derive(Hash, PartialEq, Eq)]52pub(crate) struct FormatStructure {53pub num_value_operands: usize,54pub has_value_list: bool,55pub num_block_operands: usize,56pub num_raw_block_operands: usize,57/// Tuples of (Rust field name / Rust type) for each immediate field.58pub imm_field_names: Vec<(&'static str, &'static str)>,59}6061impl fmt::Display for InstructionFormat {62fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {63let imm_args = self64.imm_fields65.iter()66.map(|field| format!("{}: {}", field.member, field.kind.rust_type))67.collect::<Vec<_>>()68.join(", ");69fmt.write_fmt(format_args!(70"{}(imms=({}), vals={}, blocks={}, raw_blocks={})",71self.name,72imm_args,73self.num_value_operands,74self.num_block_operands,75self.num_raw_block_operands,76))?;77Ok(())78}79}8081impl InstructionFormat {82/// Returns a tuple that uniquely identifies the structure.83pub fn structure(&self) -> FormatStructure {84FormatStructure {85num_value_operands: self.num_value_operands,86has_value_list: self.has_value_list,87num_block_operands: self.num_block_operands,88num_raw_block_operands: self.num_raw_block_operands,89imm_field_names: self90.imm_fields91.iter()92.map(|field| (field.kind.rust_field_name, field.kind.rust_type))93.collect::<Vec<_>>(),94}95}96}9798pub(crate) struct InstructionFormatBuilder(InstructionFormat);99100impl InstructionFormatBuilder {101pub fn new(name: &'static str) -> Self {102Self(InstructionFormat {103name,104num_value_operands: 0,105has_value_list: false,106num_block_operands: 0,107num_raw_block_operands: 0,108imm_fields: Vec::new(),109typevar_operand: None,110})111}112113pub fn value(mut self) -> Self {114self.0.num_value_operands += 1;115self116}117118pub fn varargs(mut self) -> Self {119self.0.has_value_list = true;120self121}122123pub fn block(mut self) -> Self {124self.0.num_block_operands += 1;125self126}127128pub fn raw_block(mut self) -> Self {129self.0.num_raw_block_operands += 1;130self131}132133pub fn imm(mut self, operand_kind: &OperandKind) -> Self {134let field = FormatField {135kind: operand_kind.clone(),136member: operand_kind.rust_field_name,137};138self.0.imm_fields.push(field);139self140}141142pub fn typevar_operand(mut self, operand_index: usize) -> Self {143assert!(self.0.typevar_operand.is_none());144assert!(operand_index < self.0.num_value_operands);145self.0.typevar_operand = Some(operand_index);146self147}148149pub fn build(mut self) -> Rc<InstructionFormat> {150if self.0.typevar_operand.is_none() && self.0.num_value_operands > 0 {151// Default to the first value operand, if there's one.152self.0.typevar_operand = Some(0);153};154155Rc::new(self.0)156}157}158159160