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 pub num_raw_block_operands: usize, 44 45 /// Index of the value input operand that is used to infer the controlling type variable. By 46 /// default, this is `0`, the first `value` operand. The index is relative to the values only, 47 /// ignoring immediate operands. 48 pub typevar_operand: Option<usize>, 49 } 50 51 /// A tuple serving as a key to deduplicate InstructionFormat. 52 #[derive(Hash, PartialEq, Eq)] 53 pub(crate) struct FormatStructure { 54 pub num_value_operands: usize, 55 pub has_value_list: bool, 56 pub num_block_operands: usize, 57 pub num_raw_block_operands: usize, 58 /// Tuples of (Rust field name / Rust type) for each immediate field. 59 pub imm_field_names: Vec<(&'static str, &'static str)>, 60 } 61 62 impl fmt::Display for InstructionFormat { fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>63 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 64 let imm_args = self 65 .imm_fields 66 .iter() 67 .map(|field| format!("{}: {}", field.member, field.kind.rust_type)) 68 .collect::<Vec<_>>() 69 .join(", "); 70 fmt.write_fmt(format_args!( 71 "{}(imms=({}), vals={}, blocks={}, raw_blocks={})", 72 self.name, 73 imm_args, 74 self.num_value_operands, 75 self.num_block_operands, 76 self.num_raw_block_operands, 77 ))?; 78 Ok(()) 79 } 80 } 81 82 impl InstructionFormat { 83 /// Returns a tuple that uniquely identifies the structure. structure(&self) -> FormatStructure84 pub fn structure(&self) -> FormatStructure { 85 FormatStructure { 86 num_value_operands: self.num_value_operands, 87 has_value_list: self.has_value_list, 88 num_block_operands: self.num_block_operands, 89 num_raw_block_operands: self.num_raw_block_operands, 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(InstructionFormat); 100 101 impl InstructionFormatBuilder { new(name: &'static str) -> Self102 pub fn new(name: &'static str) -> Self { 103 Self(InstructionFormat { 104 name, 105 num_value_operands: 0, 106 has_value_list: false, 107 num_block_operands: 0, 108 num_raw_block_operands: 0, 109 imm_fields: Vec::new(), 110 typevar_operand: None, 111 }) 112 } 113 value(mut self) -> Self114 pub fn value(mut self) -> Self { 115 self.0.num_value_operands += 1; 116 self 117 } 118 varargs(mut self) -> Self119 pub fn varargs(mut self) -> Self { 120 self.0.has_value_list = true; 121 self 122 } 123 block(mut self) -> Self124 pub fn block(mut self) -> Self { 125 self.0.num_block_operands += 1; 126 self 127 } 128 raw_block(mut self) -> Self129 pub fn raw_block(mut self) -> Self { 130 self.0.num_raw_block_operands += 1; 131 self 132 } 133 imm(mut self, operand_kind: &OperandKind) -> Self134 pub fn imm(mut self, operand_kind: &OperandKind) -> Self { 135 let field = FormatField { 136 kind: operand_kind.clone(), 137 member: operand_kind.rust_field_name, 138 }; 139 self.0.imm_fields.push(field); 140 self 141 } 142 typevar_operand(mut self, operand_index: usize) -> Self143 pub fn typevar_operand(mut self, operand_index: usize) -> Self { 144 assert!(self.0.typevar_operand.is_none()); 145 assert!(operand_index < self.0.num_value_operands); 146 self.0.typevar_operand = Some(operand_index); 147 self 148 } 149 build(mut self) -> Rc<InstructionFormat>150 pub fn build(mut self) -> Rc<InstructionFormat> { 151 if self.0.typevar_operand.is_none() && self.0.num_value_operands > 0 { 152 // Default to the first value operand, if there's one. 153 self.0.typevar_operand = Some(0); 154 }; 155 156 Rc::new(self.0) 157 } 158 } 159