1 use std::fmt; 2 use std::rc::Rc; 3 4 use crate::cdsl::camel_case; 5 use crate::cdsl::formats::InstructionFormat; 6 use crate::cdsl::operands::Operand; 7 use crate::cdsl::typevar::TypeVar; 8 9 pub(crate) type AllInstructions = Vec<Instruction>; 10 11 pub(crate) struct InstructionGroupBuilder<'all_inst> { 12 all_instructions: &'all_inst mut AllInstructions, 13 } 14 15 impl<'all_inst> InstructionGroupBuilder<'all_inst> { 16 pub fn new(all_instructions: &'all_inst mut AllInstructions) -> Self { 17 Self { all_instructions } 18 } 19 20 pub fn push(&mut self, builder: InstructionBuilder) { 21 let inst = builder.build(); 22 self.all_instructions.push(inst); 23 } 24 } 25 26 #[derive(Debug)] 27 pub(crate) struct PolymorphicInfo { 28 pub use_typevar_operand: bool, 29 pub ctrl_typevar: TypeVar, 30 } 31 32 #[derive(Debug)] 33 pub(crate) struct InstructionContent { 34 /// Instruction mnemonic, also becomes opcode name. 35 pub name: String, 36 pub camel_name: String, 37 38 /// Documentation string. 39 pub doc: String, 40 41 /// Input operands. This can be a mix of SSA value operands and other operand kinds. 42 pub operands_in: Vec<Operand>, 43 /// Output operands. The output operands must be SSA values or `variable_args`. 44 pub operands_out: Vec<Operand>, 45 46 /// Instruction format. 47 pub format: Rc<InstructionFormat>, 48 49 /// One of the input or output operands is a free type variable. None if the instruction is not 50 /// polymorphic, set otherwise. 51 pub polymorphic_info: Option<PolymorphicInfo>, 52 53 /// Indices in operands_in of input operands that are values. 54 pub value_opnums: Vec<usize>, 55 /// Indices in operands_in of input operands that are immediates or entities. 56 pub imm_opnums: Vec<usize>, 57 /// Indices in operands_out of output operands that are values. 58 pub value_results: Vec<usize>, 59 60 /// True for instructions that terminate the block. 61 pub is_terminator: bool, 62 /// True for all branch or jump instructions. 63 pub is_branch: bool, 64 /// Is this a call instruction? 65 pub is_call: bool, 66 /// Is this a return instruction? 67 pub is_return: bool, 68 /// Can this instruction read from memory? 69 pub can_load: bool, 70 /// Can this instruction write to memory? 71 pub can_store: bool, 72 /// Can this instruction cause a trap? 73 pub can_trap: bool, 74 /// Does this instruction have other side effects besides can_* flags? 75 pub other_side_effects: bool, 76 /// Does this instruction write to CPU flags? 77 pub writes_cpu_flags: bool, 78 } 79 80 impl InstructionContent { 81 pub fn snake_name(&self) -> &str { 82 if &self.name == "return" { 83 "return_" 84 } else { 85 &self.name 86 } 87 } 88 } 89 90 pub(crate) type Instruction = Rc<InstructionContent>; 91 92 impl fmt::Display for InstructionContent { 93 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 94 if !self.operands_out.is_empty() { 95 let operands_out = self 96 .operands_out 97 .iter() 98 .map(|op| op.name) 99 .collect::<Vec<_>>() 100 .join(", "); 101 fmt.write_str(&operands_out)?; 102 fmt.write_str(" = ")?; 103 } 104 105 fmt.write_str(&self.name)?; 106 107 if !self.operands_in.is_empty() { 108 let operands_in = self 109 .operands_in 110 .iter() 111 .map(|op| op.name) 112 .collect::<Vec<_>>() 113 .join(", "); 114 fmt.write_str(" ")?; 115 fmt.write_str(&operands_in)?; 116 } 117 118 Ok(()) 119 } 120 } 121 122 pub(crate) struct InstructionBuilder { 123 name: String, 124 doc: String, 125 format: Rc<InstructionFormat>, 126 operands_in: Option<Vec<Operand>>, 127 operands_out: Option<Vec<Operand>>, 128 129 // See Instruction comments for the meaning of these fields. 130 is_terminator: bool, 131 is_branch: bool, 132 is_call: bool, 133 is_return: bool, 134 can_load: bool, 135 can_store: bool, 136 can_trap: bool, 137 other_side_effects: bool, 138 } 139 140 impl InstructionBuilder { 141 pub fn new<S: Into<String>>(name: S, doc: S, format: &Rc<InstructionFormat>) -> Self { 142 Self { 143 name: name.into(), 144 doc: doc.into(), 145 format: format.clone(), 146 operands_in: None, 147 operands_out: None, 148 149 is_terminator: false, 150 is_branch: false, 151 is_call: false, 152 is_return: false, 153 can_load: false, 154 can_store: false, 155 can_trap: false, 156 other_side_effects: false, 157 } 158 } 159 160 pub fn operands_in(mut self, operands: Vec<&Operand>) -> Self { 161 assert!(self.operands_in.is_none()); 162 self.operands_in = Some(operands.iter().map(|x| (*x).clone()).collect()); 163 self 164 } 165 166 pub fn operands_out(mut self, operands: Vec<&Operand>) -> Self { 167 assert!(self.operands_out.is_none()); 168 self.operands_out = Some(operands.iter().map(|x| (*x).clone()).collect()); 169 self 170 } 171 172 #[allow(clippy::wrong_self_convention)] 173 pub fn is_terminator(mut self, val: bool) -> Self { 174 self.is_terminator = val; 175 self 176 } 177 178 #[allow(clippy::wrong_self_convention)] 179 pub fn is_branch(mut self, val: bool) -> Self { 180 self.is_branch = val; 181 self 182 } 183 184 #[allow(clippy::wrong_self_convention)] 185 pub fn is_call(mut self, val: bool) -> Self { 186 self.is_call = val; 187 self 188 } 189 190 #[allow(clippy::wrong_self_convention)] 191 pub fn is_return(mut self, val: bool) -> Self { 192 self.is_return = val; 193 self 194 } 195 196 pub fn can_load(mut self, val: bool) -> Self { 197 self.can_load = val; 198 self 199 } 200 201 pub fn can_store(mut self, val: bool) -> Self { 202 self.can_store = val; 203 self 204 } 205 206 pub fn can_trap(mut self, val: bool) -> Self { 207 self.can_trap = val; 208 self 209 } 210 211 pub fn other_side_effects(mut self, val: bool) -> Self { 212 self.other_side_effects = val; 213 self 214 } 215 216 fn build(self) -> Instruction { 217 let operands_in = self.operands_in.unwrap_or_else(Vec::new); 218 let operands_out = self.operands_out.unwrap_or_else(Vec::new); 219 220 let mut value_opnums = Vec::new(); 221 let mut imm_opnums = Vec::new(); 222 for (i, op) in operands_in.iter().enumerate() { 223 if op.is_value() { 224 value_opnums.push(i); 225 } else if op.is_immediate_or_entityref() { 226 imm_opnums.push(i); 227 } else { 228 assert!(op.is_varargs()); 229 } 230 } 231 232 let value_results = operands_out 233 .iter() 234 .enumerate() 235 .filter_map(|(i, op)| if op.is_value() { Some(i) } else { None }) 236 .collect(); 237 238 verify_format(&self.name, &operands_in, &self.format); 239 240 let polymorphic_info = 241 verify_polymorphic(&operands_in, &operands_out, &self.format, &value_opnums); 242 243 // Infer from output operands whether an instruction clobbers CPU flags or not. 244 let writes_cpu_flags = operands_out.iter().any(|op| op.is_cpu_flags()); 245 246 let camel_name = camel_case(&self.name); 247 248 Rc::new(InstructionContent { 249 name: self.name, 250 camel_name, 251 doc: self.doc, 252 operands_in, 253 operands_out, 254 format: self.format, 255 polymorphic_info, 256 value_opnums, 257 value_results, 258 imm_opnums, 259 is_terminator: self.is_terminator, 260 is_branch: self.is_branch, 261 is_call: self.is_call, 262 is_return: self.is_return, 263 can_load: self.can_load, 264 can_store: self.can_store, 265 can_trap: self.can_trap, 266 other_side_effects: self.other_side_effects, 267 writes_cpu_flags, 268 }) 269 } 270 } 271 272 /// Checks that the input operands actually match the given format. 273 fn verify_format(inst_name: &str, operands_in: &[Operand], format: &InstructionFormat) { 274 // A format is defined by: 275 // - its number of input value operands, 276 // - its number and names of input immediate operands, 277 // - whether it has a value list or not. 278 let mut num_values = 0; 279 let mut num_immediates = 0; 280 281 for operand in operands_in.iter() { 282 if operand.is_varargs() { 283 assert!( 284 format.has_value_list, 285 "instruction {} has varargs, but its format {} doesn't have a value list; you may \ 286 need to use a different format.", 287 inst_name, format.name 288 ); 289 } 290 if operand.is_value() { 291 num_values += 1; 292 } 293 if operand.is_immediate_or_entityref() { 294 if let Some(format_field) = format.imm_fields.get(num_immediates) { 295 assert_eq!( 296 format_field.kind.rust_field_name, 297 operand.kind.rust_field_name, 298 "{}th operand of {} should be {} (according to format), not {} (according to \ 299 inst definition). You may need to use a different format.", 300 num_immediates, 301 inst_name, 302 format_field.kind.rust_field_name, 303 operand.kind.rust_field_name 304 ); 305 num_immediates += 1; 306 } 307 } 308 } 309 310 assert_eq!( 311 num_values, format.num_value_operands, 312 "inst {} doesn't have as many value input operands as its format {} declares; you may need \ 313 to use a different format.", 314 inst_name, format.name 315 ); 316 317 assert_eq!( 318 num_immediates, 319 format.imm_fields.len(), 320 "inst {} doesn't have as many immediate input \ 321 operands as its format {} declares; you may need to use a different format.", 322 inst_name, 323 format.name 324 ); 325 } 326 327 /// Check if this instruction is polymorphic, and verify its use of type variables. 328 fn verify_polymorphic( 329 operands_in: &[Operand], 330 operands_out: &[Operand], 331 format: &InstructionFormat, 332 value_opnums: &[usize], 333 ) -> Option<PolymorphicInfo> { 334 // The instruction is polymorphic if it has one free input or output operand. 335 let is_polymorphic = operands_in 336 .iter() 337 .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some()) 338 || operands_out 339 .iter() 340 .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some()); 341 342 if !is_polymorphic { 343 return None; 344 } 345 346 // Verify the use of type variables. 347 let tv_op = format.typevar_operand; 348 let mut maybe_error_message = None; 349 if let Some(tv_op) = tv_op { 350 if tv_op < value_opnums.len() { 351 let op_num = value_opnums[tv_op]; 352 let tv = operands_in[op_num].type_var().unwrap(); 353 let free_typevar = tv.free_typevar(); 354 if (free_typevar.is_some() && tv == &free_typevar.unwrap()) 355 || tv.singleton_type().is_some() 356 { 357 match is_ctrl_typevar_candidate(tv, &operands_in, &operands_out) { 358 Ok(_other_typevars) => { 359 return Some(PolymorphicInfo { 360 use_typevar_operand: true, 361 ctrl_typevar: tv.clone(), 362 }); 363 } 364 Err(error_message) => { 365 maybe_error_message = Some(error_message); 366 } 367 } 368 } 369 } 370 }; 371 372 // If we reached here, it means the type variable indicated as the typevar operand couldn't 373 // control every other input and output type variable. We need to look at the result type 374 // variables. 375 if operands_out.is_empty() { 376 // No result means no other possible type variable, so it's a type inference failure. 377 match maybe_error_message { 378 Some(msg) => panic!("{}", msg), 379 None => panic!("typevar_operand must be a free type variable"), 380 } 381 } 382 383 // Otherwise, try to infer the controlling type variable by looking at the first result. 384 let tv = operands_out[0].type_var().unwrap(); 385 let free_typevar = tv.free_typevar(); 386 if free_typevar.is_some() && tv != &free_typevar.unwrap() { 387 panic!("first result must be a free type variable"); 388 } 389 390 // At this point, if the next unwrap() fails, it means the output type couldn't be used as a 391 // controlling type variable either; panicking is the right behavior. 392 is_ctrl_typevar_candidate(tv, &operands_in, &operands_out).unwrap(); 393 394 Some(PolymorphicInfo { 395 use_typevar_operand: false, 396 ctrl_typevar: tv.clone(), 397 }) 398 } 399 400 /// Verify that the use of TypeVars is consistent with `ctrl_typevar` as the controlling type 401 /// variable. 402 /// 403 /// All polymorhic inputs must either be derived from `ctrl_typevar` or be independent free type 404 /// variables only used once. 405 /// 406 /// All polymorphic results must be derived from `ctrl_typevar`. 407 /// 408 /// Return a vector of other type variables used, or a string explaining what went wrong. 409 fn is_ctrl_typevar_candidate( 410 ctrl_typevar: &TypeVar, 411 operands_in: &[Operand], 412 operands_out: &[Operand], 413 ) -> Result<Vec<TypeVar>, String> { 414 let mut other_typevars = Vec::new(); 415 416 // Check value inputs. 417 for input in operands_in { 418 if !input.is_value() { 419 continue; 420 } 421 422 let typ = input.type_var().unwrap(); 423 let free_typevar = typ.free_typevar(); 424 425 // Non-polymorphic or derived from ctrl_typevar is OK. 426 if free_typevar.is_none() { 427 continue; 428 } 429 let free_typevar = free_typevar.unwrap(); 430 if &free_typevar == ctrl_typevar { 431 continue; 432 } 433 434 // No other derived typevars allowed. 435 if typ != &free_typevar { 436 return Err(format!( 437 "{:?}: type variable {} must be derived from {:?} while it is derived from {:?}", 438 input, typ.name, ctrl_typevar, free_typevar 439 )); 440 } 441 442 // Other free type variables can only be used once each. 443 for other_tv in &other_typevars { 444 if &free_typevar == other_tv { 445 return Err(format!( 446 "non-controlling type variable {} can't be used more than once", 447 free_typevar.name 448 )); 449 } 450 } 451 452 other_typevars.push(free_typevar); 453 } 454 455 // Check outputs. 456 for result in operands_out { 457 if !result.is_value() { 458 continue; 459 } 460 461 let typ = result.type_var().unwrap(); 462 let free_typevar = typ.free_typevar(); 463 464 // Non-polymorphic or derived from ctrl_typevar is OK. 465 if free_typevar.is_none() || &free_typevar.unwrap() == ctrl_typevar { 466 continue; 467 } 468 469 return Err("type variable in output not derived from ctrl_typevar".into()); 470 } 471 472 Ok(other_typevars) 473 } 474