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_immediates = 0; 292 293 for operand in operands_in.iter() { 294 if operand.is_varargs() { 295 assert!( 296 format.has_value_list, 297 "instruction {} has varargs, but its format {} doesn't have a value list; you may \ 298 need to use a different format.", 299 inst_name, format.name 300 ); 301 } 302 if operand.is_value() { 303 num_values += 1; 304 } 305 if operand.kind.is_block() { 306 num_blocks += 1; 307 } else if operand.is_immediate_or_entityref() { 308 if let Some(format_field) = format.imm_fields.get(num_immediates) { 309 assert_eq!( 310 format_field.kind.rust_field_name, 311 operand.kind.rust_field_name, 312 "{}th operand of {} should be {} (according to format), not {} (according to \ 313 inst definition). You may need to use a different format.", 314 num_immediates, 315 inst_name, 316 format_field.kind.rust_field_name, 317 operand.kind.rust_field_name 318 ); 319 num_immediates += 1; 320 } 321 } 322 } 323 324 assert_eq!( 325 num_values, format.num_value_operands, 326 "inst {} doesn't have as many value input operands as its format {} declares; you may need \ 327 to use a different format.", 328 inst_name, format.name 329 ); 330 331 assert_eq!( 332 num_blocks, format.num_block_operands, 333 "inst {} doesn't have as many block input operands as its format {} declares; you may need \ 334 to use a different format.", 335 inst_name, format.name, 336 ); 337 338 assert_eq!( 339 num_immediates, 340 format.imm_fields.len(), 341 "inst {} doesn't have as many immediate input \ 342 operands as its format {} declares; you may need to use a different format.", 343 inst_name, 344 format.name 345 ); 346 } 347 348 /// Check if this instruction is polymorphic, and verify its use of type variables. 349 fn verify_polymorphic( 350 operands_in: &[Operand], 351 operands_out: &[Operand], 352 format: &InstructionFormat, 353 value_opnums: &[usize], 354 ) -> Option<PolymorphicInfo> { 355 // The instruction is polymorphic if it has one free input or output operand. 356 let is_polymorphic = operands_in 357 .iter() 358 .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some()) 359 || operands_out 360 .iter() 361 .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some()); 362 363 if !is_polymorphic { 364 return None; 365 } 366 367 // Verify the use of type variables. 368 let tv_op = format.typevar_operand; 369 let mut maybe_error_message = None; 370 if let Some(tv_op) = tv_op { 371 if tv_op < value_opnums.len() { 372 let op_num = value_opnums[tv_op]; 373 let tv = operands_in[op_num].type_var().unwrap(); 374 let free_typevar = tv.free_typevar(); 375 if (free_typevar.is_some() && tv == &free_typevar.unwrap()) 376 || tv.singleton_type().is_some() 377 { 378 match is_ctrl_typevar_candidate(tv, operands_in, operands_out) { 379 Ok(_other_typevars) => { 380 return Some(PolymorphicInfo { 381 use_typevar_operand: true, 382 ctrl_typevar: tv.clone(), 383 }); 384 } 385 Err(error_message) => { 386 maybe_error_message = Some(error_message); 387 } 388 } 389 } 390 } 391 }; 392 393 // If we reached here, it means the type variable indicated as the typevar operand couldn't 394 // control every other input and output type variable. We need to look at the result type 395 // variables. 396 if operands_out.is_empty() { 397 // No result means no other possible type variable, so it's a type inference failure. 398 match maybe_error_message { 399 Some(msg) => panic!("{}", msg), 400 None => panic!("typevar_operand must be a free type variable"), 401 } 402 } 403 404 // Otherwise, try to infer the controlling type variable by looking at the first result. 405 let tv = operands_out[0].type_var().unwrap(); 406 let free_typevar = tv.free_typevar(); 407 if free_typevar.is_some() && tv != &free_typevar.unwrap() { 408 panic!("first result must be a free type variable"); 409 } 410 411 // At this point, if the next unwrap() fails, it means the output type couldn't be used as a 412 // controlling type variable either; panicking is the right behavior. 413 is_ctrl_typevar_candidate(tv, operands_in, operands_out).unwrap(); 414 415 Some(PolymorphicInfo { 416 use_typevar_operand: false, 417 ctrl_typevar: tv.clone(), 418 }) 419 } 420 421 /// Verify that the use of TypeVars is consistent with `ctrl_typevar` as the controlling type 422 /// variable. 423 /// 424 /// All polymorphic inputs must either be derived from `ctrl_typevar` or be independent free type 425 /// variables only used once. 426 /// 427 /// All polymorphic results must be derived from `ctrl_typevar`. 428 /// 429 /// Return a vector of other type variables used, or a string explaining what went wrong. 430 fn is_ctrl_typevar_candidate( 431 ctrl_typevar: &TypeVar, 432 operands_in: &[Operand], 433 operands_out: &[Operand], 434 ) -> Result<Vec<TypeVar>, String> { 435 let mut other_typevars = Vec::new(); 436 437 // Check value inputs. 438 for input in operands_in { 439 if !input.is_value() { 440 continue; 441 } 442 443 let typ = input.type_var().unwrap(); 444 let free_typevar = typ.free_typevar(); 445 446 // Non-polymorphic or derived from ctrl_typevar is OK. 447 if free_typevar.is_none() { 448 continue; 449 } 450 let free_typevar = free_typevar.unwrap(); 451 if &free_typevar == ctrl_typevar { 452 continue; 453 } 454 455 // No other derived typevars allowed. 456 if typ != &free_typevar { 457 return Err(format!( 458 "{:?}: type variable {} must be derived from {:?} while it is derived from {:?}", 459 input, typ.name, ctrl_typevar, free_typevar 460 )); 461 } 462 463 // Other free type variables can only be used once each. 464 for other_tv in &other_typevars { 465 if &free_typevar == other_tv { 466 return Err(format!( 467 "non-controlling type variable {} can't be used more than once", 468 free_typevar.name 469 )); 470 } 471 } 472 473 other_typevars.push(free_typevar); 474 } 475 476 // Check outputs. 477 for result in operands_out { 478 if !result.is_value() { 479 continue; 480 } 481 482 let typ = result.type_var().unwrap(); 483 let free_typevar = typ.free_typevar(); 484 485 // Non-polymorphic or derived from ctrl_typevar is OK. 486 if free_typevar.is_none() || &free_typevar.unwrap() == ctrl_typevar { 487 continue; 488 } 489 490 return Err("type variable in output not derived from ctrl_typevar".into()); 491 } 492 493 Ok(other_typevars) 494 } 495