1 use crate::cdsl::operands::OperandKind; 2 use std::fmt; 3 use std::rc::Rc; 4 5 /// An immediate field in an instruction format. 6 /// 7 /// This corresponds to a single member of a variant of the `InstructionData` 8 /// data type. 9 #[derive(Debug)] 10 pub(crate) struct FormatField { 11 /// Immediate operand kind. 12 pub kind: OperandKind, 13 14 /// Member name in InstructionData variant. 15 pub member: &'static str, 16 } 17 18 /// Every instruction opcode has a corresponding instruction format which determines the number of 19 /// operands and their kinds. Instruction formats are identified structurally, i.e., the format of 20 /// an instruction is derived from the kinds of operands used in its declaration. 21 /// 22 /// The instruction format stores two separate lists of operands: Immediates and values. Immediate 23 /// operands (including entity references) are represented as explicit members in the 24 /// `InstructionData` variants. The value operands are stored differently, depending on how many 25 /// there are. Beyond a certain point, instruction formats switch to an external value list for 26 /// storing value arguments. Value lists can hold an arbitrary number of values. 27 /// 28 /// All instruction formats must be predefined in the meta shared/formats.rs module. 29 #[derive(Debug)] 30 pub(crate) struct InstructionFormat { 31 /// Instruction format name in CamelCase. This is used as a Rust variant name in both the 32 /// `InstructionData` and `InstructionFormat` enums. 33 pub name: &'static str, 34 35 pub num_value_operands: usize, 36 37 pub has_value_list: bool, 38 39 pub imm_fields: Vec<FormatField>, 40 41 pub num_block_operands: usize, 42 43 /// Index of the value input operand that is used to infer the controlling type variable. By 44 /// default, this is `0`, the first `value` operand. The index is relative to the values only, 45 /// ignoring immediate operands. 46 pub typevar_operand: Option<usize>, 47 } 48 49 /// A tuple serving as a key to deduplicate InstructionFormat. 50 #[derive(Hash, PartialEq, Eq)] 51 pub(crate) struct FormatStructure { 52 pub num_value_operands: usize, 53 pub has_value_list: bool, 54 pub num_block_operands: usize, 55 /// Tuples of (Rust field name / Rust type) for each immediate field. 56 pub imm_field_names: Vec<(&'static str, &'static str)>, 57 } 58 59 impl fmt::Display for InstructionFormat { 60 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 61 let imm_args = self 62 .imm_fields 63 .iter() 64 .map(|field| format!("{}: {}", field.member, field.kind.rust_type)) 65 .collect::<Vec<_>>() 66 .join(", "); 67 fmt.write_fmt(format_args!( 68 "{}(imms=({}), vals={}, blocks={})", 69 self.name, imm_args, self.num_value_operands, self.num_block_operands, 70 ))?; 71 Ok(()) 72 } 73 } 74 75 impl InstructionFormat { 76 /// Returns a tuple that uniquely identifies the structure. 77 pub fn structure(&self) -> FormatStructure { 78 FormatStructure { 79 num_value_operands: self.num_value_operands, 80 has_value_list: self.has_value_list, 81 num_block_operands: self.num_block_operands, 82 imm_field_names: self 83 .imm_fields 84 .iter() 85 .map(|field| (field.kind.rust_field_name, field.kind.rust_type)) 86 .collect::<Vec<_>>(), 87 } 88 } 89 } 90 91 pub(crate) struct InstructionFormatBuilder(InstructionFormat); 92 93 impl InstructionFormatBuilder { 94 pub fn new(name: &'static str) -> Self { 95 Self(InstructionFormat { 96 name, 97 num_value_operands: 0, 98 has_value_list: false, 99 num_block_operands: 0, 100 imm_fields: Vec::new(), 101 typevar_operand: None, 102 }) 103 } 104 105 pub fn value(mut self) -> Self { 106 self.0.num_value_operands += 1; 107 self 108 } 109 110 pub fn varargs(mut self) -> Self { 111 self.0.has_value_list = true; 112 self 113 } 114 115 pub fn block(mut self) -> Self { 116 self.0.num_block_operands += 1; 117 self 118 } 119 120 pub fn imm(mut self, operand_kind: &OperandKind) -> Self { 121 let field = FormatField { 122 kind: operand_kind.clone(), 123 member: operand_kind.rust_field_name, 124 }; 125 self.0.imm_fields.push(field); 126 self 127 } 128 129 pub fn typevar_operand(mut self, operand_index: usize) -> Self { 130 assert!(self.0.typevar_operand.is_none()); 131 assert!(operand_index < self.0.num_value_operands); 132 self.0.typevar_operand = Some(operand_index); 133 self 134 } 135 136 pub fn build(mut self) -> Rc<InstructionFormat> { 137 if self.0.typevar_operand.is_none() && self.0.num_value_operands > 0 { 138 // Default to the first value operand, if there's one. 139 self.0.typevar_operand = Some(0); 140 }; 141 142 Rc::new(self.0) 143 } 144 } 145