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 /// Index of the value input operand that is used to infer the controlling type variable. By 42 /// default, this is `0`, the first `value` operand. The index is relative to the values only, 43 /// ignoring immediate operands. 44 pub typevar_operand: Option<usize>, 45 } 46 47 /// A tuple serving as a key to deduplicate InstructionFormat. 48 #[derive(Hash, PartialEq, Eq)] 49 pub(crate) struct FormatStructure { 50 pub num_value_operands: usize, 51 pub has_value_list: bool, 52 /// Tuples of (Rust field name / Rust type) for each immediate field. 53 pub imm_field_names: Vec<(&'static str, &'static str)>, 54 } 55 56 impl fmt::Display for InstructionFormat { fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>57 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 58 let imm_args = self 59 .imm_fields 60 .iter() 61 .map(|field| format!("{}: {}", field.member, field.kind.rust_type)) 62 .collect::<Vec<_>>() 63 .join(", "); 64 fmt.write_fmt(format_args!( 65 "{}(imms=({}), vals={})", 66 self.name, imm_args, self.num_value_operands 67 ))?; 68 Ok(()) 69 } 70 } 71 72 impl InstructionFormat { imm_by_name(&self, name: &'static str) -> &FormatField73 pub fn imm_by_name(&self, name: &'static str) -> &FormatField { 74 self.imm_fields 75 .iter() 76 .find(|&field| field.member == name) 77 .unwrap_or_else(|| { 78 panic!( 79 "unexpected immediate field named {} in instruction format {}", 80 name, self.name 81 ) 82 }) 83 } 84 85 /// Returns a tuple that uniquely identifies the structure. structure(&self) -> FormatStructure86 pub fn structure(&self) -> FormatStructure { 87 FormatStructure { 88 num_value_operands: self.num_value_operands, 89 has_value_list: self.has_value_list, 90 imm_field_names: self 91 .imm_fields 92 .iter() 93 .map(|field| (field.kind.rust_field_name, field.kind.rust_type)) 94 .collect::<Vec<_>>(), 95 } 96 } 97 } 98 99 pub(crate) struct InstructionFormatBuilder { 100 name: &'static str, 101 num_value_operands: usize, 102 has_value_list: bool, 103 imm_fields: Vec<FormatField>, 104 typevar_operand: Option<usize>, 105 } 106 107 impl InstructionFormatBuilder { new(name: &'static str) -> Self108 pub fn new(name: &'static str) -> Self { 109 Self { 110 name, 111 num_value_operands: 0, 112 has_value_list: false, 113 imm_fields: Vec::new(), 114 typevar_operand: None, 115 } 116 } 117 value(mut self) -> Self118 pub fn value(mut self) -> Self { 119 self.num_value_operands += 1; 120 self 121 } 122 varargs(mut self) -> Self123 pub fn varargs(mut self) -> Self { 124 self.has_value_list = true; 125 self 126 } 127 imm(mut self, operand_kind: &OperandKind) -> Self128 pub fn imm(mut self, operand_kind: &OperandKind) -> Self { 129 let field = FormatField { 130 kind: operand_kind.clone(), 131 member: operand_kind.rust_field_name, 132 }; 133 self.imm_fields.push(field); 134 self 135 } 136 imm_with_name(mut self, member: &'static str, operand_kind: &OperandKind) -> Self137 pub fn imm_with_name(mut self, member: &'static str, operand_kind: &OperandKind) -> Self { 138 let field = FormatField { 139 kind: operand_kind.clone(), 140 member, 141 }; 142 self.imm_fields.push(field); 143 self 144 } 145 typevar_operand(mut self, operand_index: usize) -> Self146 pub fn typevar_operand(mut self, operand_index: usize) -> Self { 147 assert!(self.typevar_operand.is_none()); 148 assert!(self.has_value_list || operand_index < self.num_value_operands); 149 self.typevar_operand = Some(operand_index); 150 self 151 } 152 build(self) -> Rc<InstructionFormat>153 pub fn build(self) -> Rc<InstructionFormat> { 154 let typevar_operand = if self.typevar_operand.is_some() { 155 self.typevar_operand 156 } else if self.has_value_list || self.num_value_operands > 0 { 157 // Default to the first value operand, if there's one. 158 Some(0) 159 } else { 160 None 161 }; 162 163 Rc::new(InstructionFormat { 164 name: self.name, 165 num_value_operands: self.num_value_operands, 166 has_value_list: self.has_value_list, 167 imm_fields: self.imm_fields, 168 typevar_operand, 169 }) 170 } 171 } 172