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 /// Despite having other side effects, is this instruction okay to GVN? 77 pub side_effects_idempotent: 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 side_effects_idempotent: bool, 139 } 140 141 impl InstructionBuilder { 142 pub fn new<S: Into<String>>(name: S, doc: S, format: &Rc<InstructionFormat>) -> Self { 143 Self { 144 name: name.into(), 145 doc: doc.into(), 146 format: format.clone(), 147 operands_in: None, 148 operands_out: None, 149 150 is_terminator: false, 151 is_branch: false, 152 is_call: false, 153 is_return: false, 154 can_load: false, 155 can_store: false, 156 can_trap: false, 157 other_side_effects: false, 158 side_effects_idempotent: false, 159 } 160 } 161 162 pub fn operands_in(mut self, operands: Vec<Operand>) -> Self { 163 assert!(self.operands_in.is_none()); 164 self.operands_in = Some(operands); 165 self 166 } 167 168 pub fn operands_out(mut self, operands: Vec<Operand>) -> Self { 169 assert!(self.operands_out.is_none()); 170 self.operands_out = Some(operands); 171 self 172 } 173 174 /// Mark this instruction as a block terminator. 175 pub fn terminates_block(mut self) -> Self { 176 self.is_terminator = true; 177 self 178 } 179 180 /// Mark this instruction as a branch instruction. This also implies that the instruction is a 181 /// block terminator. 182 pub fn branches(mut self) -> Self { 183 self.is_branch = true; 184 self.terminates_block() 185 } 186 187 /// Mark this instruction as a call instruction. 188 pub fn call(mut self) -> Self { 189 self.is_call = true; 190 self 191 } 192 193 /// Mark this instruction as a return instruction. This also implies that the instruction is a 194 /// block terminator. 195 pub fn returns(mut self) -> Self { 196 self.is_return = true; 197 self.terminates_block() 198 } 199 200 /// Mark this instruction as one that can load from memory. 201 pub fn can_load(mut self) -> Self { 202 self.can_load = true; 203 self 204 } 205 206 /// Mark this instruction as one that can store to memory. 207 pub fn can_store(mut self) -> Self { 208 self.can_store = true; 209 self 210 } 211 212 /// Mark this instruction as possibly trapping. 213 pub fn can_trap(mut self) -> Self { 214 self.can_trap = true; 215 self 216 } 217 218 /// Mark this instruction as one that has side-effects. 219 pub fn other_side_effects(mut self) -> Self { 220 self.other_side_effects = true; 221 self 222 } 223 224 /// Mark this instruction as one whose side-effects may be de-duplicated. 225 pub fn side_effects_idempotent(mut self) -> Self { 226 self.side_effects_idempotent = true; 227 self 228 } 229 230 fn build(self) -> Instruction { 231 let operands_in = self.operands_in.unwrap_or_default(); 232 let operands_out = self.operands_out.unwrap_or_default(); 233 234 let mut value_opnums = Vec::new(); 235 let mut imm_opnums = Vec::new(); 236 for (i, op) in operands_in.iter().enumerate() { 237 if op.is_value() { 238 value_opnums.push(i); 239 } else if op.is_immediate_or_entityref() { 240 imm_opnums.push(i); 241 } else { 242 assert!(op.is_varargs()); 243 } 244 } 245 246 let value_results = operands_out 247 .iter() 248 .enumerate() 249 .filter_map(|(i, op)| if op.is_value() { Some(i) } else { None }) 250 .collect(); 251 252 verify_format(&self.name, &operands_in, &self.format); 253 254 let polymorphic_info = 255 verify_polymorphic(&operands_in, &operands_out, &self.format, &value_opnums); 256 257 let camel_name = camel_case(&self.name); 258 259 Rc::new(InstructionContent { 260 name: self.name, 261 camel_name, 262 doc: self.doc, 263 operands_in, 264 operands_out, 265 format: self.format, 266 polymorphic_info, 267 value_opnums, 268 value_results, 269 imm_opnums, 270 is_terminator: self.is_terminator, 271 is_branch: self.is_branch, 272 is_call: self.is_call, 273 is_return: self.is_return, 274 can_load: self.can_load, 275 can_store: self.can_store, 276 can_trap: self.can_trap, 277 other_side_effects: self.other_side_effects, 278 side_effects_idempotent: self.side_effects_idempotent, 279 }) 280 } 281 } 282 283 /// Checks that the input operands actually match the given format. 284 fn verify_format(inst_name: &str, operands_in: &[Operand], format: &InstructionFormat) { 285 // A format is defined by: 286 // - its number of input value operands, 287 // - its number and names of input immediate operands, 288 // - whether it has a value list or not. 289 let mut num_values = 0; 290 let mut num_blocks = 0; 291 let mut num_raw_blocks = 0; 292 let mut num_immediates = 0; 293 294 for operand in operands_in.iter() { 295 if operand.is_varargs() { 296 assert!( 297 format.has_value_list, 298 "instruction {} has varargs, but its format {} doesn't have a value list; you may \ 299 need to use a different format.", 300 inst_name, format.name 301 ); 302 } 303 if operand.is_value() { 304 num_values += 1; 305 } 306 if operand.kind.is_block() { 307 num_blocks += 1; 308 } else if operand.kind.is_raw_block() { 309 num_raw_blocks += 1; 310 } else if operand.is_immediate_or_entityref() { 311 if let Some(format_field) = format.imm_fields.get(num_immediates) { 312 assert_eq!( 313 format_field.kind.rust_field_name, 314 operand.kind.rust_field_name, 315 "{}th operand of {} should be {} (according to format), not {} (according to \ 316 inst definition). You may need to use a different format.", 317 num_immediates, 318 inst_name, 319 format_field.kind.rust_field_name, 320 operand.kind.rust_field_name 321 ); 322 num_immediates += 1; 323 } 324 } 325 } 326 327 assert_eq!( 328 num_values, format.num_value_operands, 329 "inst {} doesn't have as many value input operands as its format {} declares; you may need \ 330 to use a different format.", 331 inst_name, format.name 332 ); 333 334 assert_eq!( 335 num_blocks, format.num_block_operands, 336 "inst {} doesn't have as many block input operands as its format {} declares; you may need \ 337 to use a different format.", 338 inst_name, format.name, 339 ); 340 341 assert_eq!( 342 num_raw_blocks, format.num_raw_block_operands, 343 "inst {} doesn't have as many raw-block input operands as its format {} declares; you may need \ 344 to use a different format.", 345 inst_name, format.name, 346 ); 347 348 assert_eq!( 349 num_immediates, 350 format.imm_fields.len(), 351 "inst {} doesn't have as many immediate input \ 352 operands as its format {} declares; you may need to use a different format.", 353 inst_name, 354 format.name 355 ); 356 } 357 358 /// Check if this instruction is polymorphic, and verify its use of type variables. 359 fn verify_polymorphic( 360 operands_in: &[Operand], 361 operands_out: &[Operand], 362 format: &InstructionFormat, 363 value_opnums: &[usize], 364 ) -> Option<PolymorphicInfo> { 365 // The instruction is polymorphic if it has one free input or output operand. 366 let is_polymorphic = operands_in 367 .iter() 368 .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some()) 369 || operands_out 370 .iter() 371 .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some()); 372 373 if !is_polymorphic { 374 return None; 375 } 376 377 // Verify the use of type variables. 378 let tv_op = format.typevar_operand; 379 let mut maybe_error_message = None; 380 if let Some(tv_op) = tv_op { 381 if tv_op < value_opnums.len() { 382 let op_num = value_opnums[tv_op]; 383 let tv = operands_in[op_num].type_var().unwrap(); 384 let free_typevar = tv.free_typevar(); 385 if (free_typevar.is_some() && tv == &free_typevar.unwrap()) 386 || tv.singleton_type().is_some() 387 { 388 match is_ctrl_typevar_candidate(tv, operands_in, operands_out) { 389 Ok(_other_typevars) => { 390 return Some(PolymorphicInfo { 391 use_typevar_operand: true, 392 ctrl_typevar: tv.clone(), 393 }); 394 } 395 Err(error_message) => { 396 maybe_error_message = Some(error_message); 397 } 398 } 399 } 400 } 401 }; 402 403 // If we reached here, it means the type variable indicated as the typevar operand couldn't 404 // control every other input and output type variable. We need to look at the result type 405 // variables. 406 if operands_out.is_empty() { 407 // No result means no other possible type variable, so it's a type inference failure. 408 match maybe_error_message { 409 Some(msg) => panic!("{}", msg), 410 None => panic!("typevar_operand must be a free type variable"), 411 } 412 } 413 414 // Otherwise, try to infer the controlling type variable by looking at the first result. 415 let tv = operands_out[0].type_var().unwrap(); 416 let free_typevar = tv.free_typevar(); 417 if free_typevar.is_some() && tv != &free_typevar.unwrap() { 418 panic!("first result must be a free type variable"); 419 } 420 421 // At this point, if the next unwrap() fails, it means the output type couldn't be used as a 422 // controlling type variable either; panicking is the right behavior. 423 is_ctrl_typevar_candidate(tv, operands_in, operands_out).unwrap(); 424 425 Some(PolymorphicInfo { 426 use_typevar_operand: false, 427 ctrl_typevar: tv.clone(), 428 }) 429 } 430 431 /// Verify that the use of TypeVars is consistent with `ctrl_typevar` as the controlling type 432 /// variable. 433 /// 434 /// All polymorphic inputs must either be derived from `ctrl_typevar` or be independent free type 435 /// variables only used once. 436 /// 437 /// All polymorphic results must be derived from `ctrl_typevar`. 438 /// 439 /// Return a vector of other type variables used, or a string explaining what went wrong. 440 fn is_ctrl_typevar_candidate( 441 ctrl_typevar: &TypeVar, 442 operands_in: &[Operand], 443 operands_out: &[Operand], 444 ) -> Result<Vec<TypeVar>, String> { 445 let mut other_typevars = Vec::new(); 446 447 // Check value inputs. 448 for input in operands_in { 449 if !input.is_value() { 450 continue; 451 } 452 453 let typ = input.type_var().unwrap(); 454 let free_typevar = typ.free_typevar(); 455 456 // Non-polymorphic or derived from ctrl_typevar is OK. 457 if free_typevar.is_none() { 458 continue; 459 } 460 let free_typevar = free_typevar.unwrap(); 461 if &free_typevar == ctrl_typevar { 462 continue; 463 } 464 465 // No other derived typevars allowed. 466 if typ != &free_typevar { 467 return Err(format!( 468 "{:?}: type variable {} must be derived from {:?} while it is derived from {:?}", 469 input, typ.name, ctrl_typevar, free_typevar 470 )); 471 } 472 473 // Other free type variables can only be used once each. 474 for other_tv in &other_typevars { 475 if &free_typevar == other_tv { 476 return Err(format!( 477 "non-controlling type variable {} can't be used more than once", 478 free_typevar.name 479 )); 480 } 481 } 482 483 other_typevars.push(free_typevar); 484 } 485 486 // Check outputs. 487 for result in operands_out { 488 if !result.is_value() { 489 continue; 490 } 491 492 let typ = result.type_var().unwrap(); 493 let free_typevar = typ.free_typevar(); 494 495 // Non-polymorphic or derived from ctrl_typevar is OK. 496 if free_typevar.is_none() || &free_typevar.unwrap() == ctrl_typevar { 497 continue; 498 } 499 500 return Err("type variable in output not derived from ctrl_typevar".into()); 501 } 502 503 Ok(other_typevars) 504 } 505