1 use std::collections::HashMap; 2 3 use crate::cdsl::typevar::TypeVar; 4 5 /// An instruction operand can be an *immediate*, an *SSA value*, or an *entity reference*. The 6 /// type of the operand is one of: 7 /// 8 /// 1. A `ValueType` instance indicates an SSA value operand with a concrete type. 9 /// 10 /// 2. A `TypeVar` instance indicates an SSA value operand, and the instruction is polymorphic over 11 /// the possible concrete types that the type variable can assume. 12 /// 13 /// 3. An `ImmediateKind` instance indicates an immediate operand whose value is encoded in the 14 /// instruction itself rather than being passed as an SSA value. 15 /// 16 /// 4. An `EntityRefKind` instance indicates an operand that references another entity in the 17 /// function, typically something declared in the function preamble. 18 #[derive(Clone, Debug)] 19 pub(crate) struct Operand { 20 /// Name of the operand variable, as it appears in function parameters, legalizations, etc. 21 pub name: &'static str, 22 23 /// Type of the operand. 24 pub kind: OperandKind, 25 26 doc: Option<&'static str>, 27 } 28 29 impl Operand { new(name: &'static str, kind: impl Into<OperandKind>) -> Self30 pub fn new(name: &'static str, kind: impl Into<OperandKind>) -> Self { 31 Self { 32 name, 33 doc: None, 34 kind: kind.into(), 35 } 36 } with_doc(mut self, doc: &'static str) -> Self37 pub fn with_doc(mut self, doc: &'static str) -> Self { 38 self.doc = Some(doc); 39 self 40 } 41 doc(&self) -> Option<&str>42 pub fn doc(&self) -> Option<&str> { 43 if let Some(doc) = &self.doc { 44 return Some(doc); 45 } 46 match &self.kind.fields { 47 OperandKindFields::TypeVar(tvar) => Some(&tvar.doc), 48 _ => self.kind.doc(), 49 } 50 } 51 is_value(&self) -> bool52 pub fn is_value(&self) -> bool { 53 match self.kind.fields { 54 OperandKindFields::TypeVar(_) => true, 55 _ => false, 56 } 57 } 58 type_var(&self) -> Option<&TypeVar>59 pub fn type_var(&self) -> Option<&TypeVar> { 60 match &self.kind.fields { 61 OperandKindFields::TypeVar(typevar) => Some(typevar), 62 _ => None, 63 } 64 } 65 is_varargs(&self) -> bool66 pub fn is_varargs(&self) -> bool { 67 match self.kind.fields { 68 OperandKindFields::VariableArgs => true, 69 _ => false, 70 } 71 } 72 73 /// Returns true if the operand has an immediate kind or is an EntityRef. is_immediate_or_entityref(&self) -> bool74 pub fn is_immediate_or_entityref(&self) -> bool { 75 match self.kind.fields { 76 OperandKindFields::ImmEnum(_) 77 | OperandKindFields::ImmValue 78 | OperandKindFields::EntityRef => true, 79 _ => false, 80 } 81 } 82 83 /// Returns true if the operand has an immediate kind. is_immediate(&self) -> bool84 pub fn is_immediate(&self) -> bool { 85 match self.kind.fields { 86 OperandKindFields::ImmEnum(_) | OperandKindFields::ImmValue => true, 87 _ => false, 88 } 89 } 90 is_cpu_flags(&self) -> bool91 pub fn is_cpu_flags(&self) -> bool { 92 match &self.kind.fields { 93 OperandKindFields::TypeVar(type_var) 94 if type_var.name == "iflags" || type_var.name == "fflags" => 95 { 96 true 97 } 98 _ => false, 99 } 100 } 101 } 102 103 pub type EnumValues = HashMap<&'static str, &'static str>; 104 105 #[derive(Clone, Debug)] 106 pub(crate) enum OperandKindFields { 107 EntityRef, 108 VariableArgs, 109 ImmValue, 110 ImmEnum(EnumValues), 111 TypeVar(TypeVar), 112 } 113 114 #[derive(Clone, Debug)] 115 pub(crate) struct OperandKind { 116 /// String representation of the Rust type mapping to this OperandKind. 117 pub rust_type: &'static str, 118 119 /// Name of this OperandKind in the format's member field. 120 pub rust_field_name: &'static str, 121 122 /// Type-specific fields for this OperandKind. 123 pub fields: OperandKindFields, 124 125 doc: Option<&'static str>, 126 } 127 128 impl OperandKind { new( rust_field_name: &'static str, rust_type: &'static str, fields: OperandKindFields, ) -> Self129 pub fn new( 130 rust_field_name: &'static str, 131 rust_type: &'static str, 132 fields: OperandKindFields, 133 ) -> Self { 134 Self { 135 rust_field_name, 136 rust_type, 137 fields, 138 doc: None, 139 } 140 } with_doc(mut self, doc: &'static str) -> Self141 pub fn with_doc(mut self, doc: &'static str) -> Self { 142 assert!(self.doc.is_none()); 143 self.doc = Some(doc); 144 self 145 } doc(&self) -> Option<&str>146 fn doc(&self) -> Option<&str> { 147 if let Some(doc) = &self.doc { 148 return Some(doc); 149 } 150 match &self.fields { 151 OperandKindFields::TypeVar(type_var) => Some(&type_var.doc), 152 OperandKindFields::ImmEnum(_) 153 | OperandKindFields::ImmValue 154 | OperandKindFields::EntityRef 155 | OperandKindFields::VariableArgs => None, 156 } 157 } 158 } 159 160 impl Into<OperandKind> for &TypeVar { into(self) -> OperandKind161 fn into(self) -> OperandKind { 162 OperandKind::new( 163 "value", 164 "ir::Value", 165 OperandKindFields::TypeVar(self.into()), 166 ) 167 } 168 } 169 impl Into<OperandKind> for &OperandKind { into(self) -> OperandKind170 fn into(self) -> OperandKind { 171 self.clone() 172 } 173 } 174