1 //! A verifier for ensuring that functions are well formed. 2 //! It verifies: 3 //! 4 //! block integrity 5 //! 6 //! - All instructions reached from the `block_insts` iterator must belong to 7 //! the block as reported by `inst_block()`. 8 //! - Every block must end in a terminator instruction, and no other instruction 9 //! can be a terminator. 10 //! - Every value in the `block_params` iterator belongs to the block as reported by `value_block`. 11 //! 12 //! Instruction integrity 13 //! 14 //! - The instruction format must match the opcode. 15 //! - All result values must be created for multi-valued instructions. 16 //! - All referenced entities must exist. (Values, blocks, stack slots, ...) 17 //! - Instructions must not reference (eg. branch to) the entry block. 18 //! 19 //! SSA form 20 //! 21 //! - Values must be defined by an instruction that exists and that is inserted in 22 //! a block, or be an argument of an existing block. 23 //! - Values used by an instruction must dominate the instruction. 24 //! 25 //! Control flow graph and dominator tree integrity: 26 //! 27 //! - All predecessors in the CFG must be branches to the block. 28 //! - All branches to a block must be present in the CFG. 29 //! - A recomputed dominator tree is identical to the existing one. 30 //! 31 //! Type checking 32 //! 33 //! - Compare input and output values against the opcode's type constraints. 34 //! For polymorphic opcodes, determine the controlling type variable first. 35 //! - Branches and jumps must pass arguments to destination blocks that match the 36 //! expected types exactly. The number of arguments must match. 37 //! - All blocks in a jump table must take no arguments. 38 //! - Function calls are type checked against their signature. 39 //! - The entry block must take arguments that match the signature of the current 40 //! function. 41 //! - All return instructions must have return value operands matching the current 42 //! function signature. 43 //! 44 //! Global values 45 //! 46 //! - Detect cycles in global values. 47 //! - Detect use of 'vmctx' global value when no corresponding parameter is defined. 48 //! 49 //! TODO: 50 //! Ad hoc checking 51 //! 52 //! - Stack slot loads and stores must be in-bounds. 53 //! - Immediate constraints for certain opcodes, like `udiv_imm v3, 0`. 54 //! - `Insertlane` and `extractlane` instructions have immediate lane numbers that must be in 55 //! range for their polymorphic type. 56 //! - Swizzle and shuffle instructions take a variable number of lane arguments. The number 57 //! of arguments must match the destination type, and the lane indexes must be in range. 58 59 use self::flags::verify_flags; 60 use crate::dbg::DisplayList; 61 use crate::dominator_tree::DominatorTree; 62 use crate::entity::SparseSet; 63 use crate::flowgraph::{BlockPredecessor, ControlFlowGraph}; 64 use crate::ir; 65 use crate::ir::entities::AnyEntity; 66 use crate::ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint}; 67 use crate::ir::{ 68 types, ArgumentLoc, ArgumentPurpose, Block, Constant, FuncRef, Function, GlobalValue, Inst, 69 InstructionData, JumpTable, Opcode, SigRef, StackSlot, StackSlotKind, Type, Value, ValueDef, 70 ValueList, ValueLoc, 71 }; 72 use crate::isa::TargetIsa; 73 use crate::iterators::IteratorExtras; 74 use crate::print_errors::pretty_verifier_error; 75 use crate::settings::FlagsOrIsa; 76 use crate::timing; 77 use alloc::collections::BTreeSet; 78 use alloc::string::{String, ToString}; 79 use alloc::vec::Vec; 80 use core::cmp::Ordering; 81 use core::fmt::{self, Display, Formatter, Write}; 82 83 pub use self::cssa::verify_cssa; 84 pub use self::liveness::verify_liveness; 85 pub use self::locations::verify_locations; 86 87 mod cssa; 88 mod flags; 89 mod liveness; 90 mod locations; 91 92 /// A verifier error. 93 #[derive(Debug, PartialEq, Eq, Clone)] 94 pub struct VerifierError { 95 /// The entity causing the verifier error. 96 pub location: AnyEntity, 97 /// Optionally provide some context for the given location; e.g., for `inst42` provide 98 /// `Some("v3 = iconst.i32 0")` for more comprehensible errors. 99 pub context: Option<String>, 100 /// The error message. 101 pub message: String, 102 } 103 104 // This is manually implementing Error and Display instead of using thiserror to reduce the amount 105 // of dependencies used by Cranelift. 106 impl std::error::Error for VerifierError {} 107 108 impl Display for VerifierError { 109 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 110 match &self.context { 111 None => write!(f, "{}: {}", self.location, self.message), 112 Some(context) => write!(f, "{} ({}): {}", self.location, context, self.message), 113 } 114 } 115 } 116 117 /// Convenience converter for making error-reporting less verbose. 118 /// 119 /// Converts a tuple of `(location, context, message)` to a `VerifierError`. 120 /// ``` 121 /// use cranelift_codegen::verifier::VerifierErrors; 122 /// use cranelift_codegen::ir::Inst; 123 /// let mut errors = VerifierErrors::new(); 124 /// errors.report((Inst::from_u32(42), "v3 = iadd v1, v2", "iadd cannot be used with values of this type")); 125 /// // note the double parenthenses to use this syntax 126 /// ``` 127 impl<L, C, M> From<(L, C, M)> for VerifierError 128 where 129 L: Into<AnyEntity>, 130 C: Into<String>, 131 M: Into<String>, 132 { 133 fn from(items: (L, C, M)) -> Self { 134 let (location, context, message) = items; 135 Self { 136 location: location.into(), 137 context: Some(context.into()), 138 message: message.into(), 139 } 140 } 141 } 142 143 /// Convenience converter for making error-reporting less verbose. 144 /// 145 /// Same as above but without `context`. 146 impl<L, M> From<(L, M)> for VerifierError 147 where 148 L: Into<AnyEntity>, 149 M: Into<String>, 150 { 151 fn from(items: (L, M)) -> Self { 152 let (location, message) = items; 153 Self { 154 location: location.into(), 155 context: None, 156 message: message.into(), 157 } 158 } 159 } 160 161 /// Result of a step in the verification process. 162 /// 163 /// Functions that return `VerifierStepResult<()>` should also take a 164 /// mutable reference to `VerifierErrors` as argument in order to report 165 /// errors. 166 /// 167 /// Here, `Ok` represents a step that **did not lead to a fatal error**, 168 /// meaning that the verification process may continue. However, other (non-fatal) 169 /// errors might have been reported through the previously mentioned `VerifierErrors` 170 /// argument. 171 pub type VerifierStepResult<T> = Result<T, ()>; 172 173 /// Result of a verification operation. 174 /// 175 /// Unlike `VerifierStepResult<()>` which may be `Ok` while still having reported 176 /// errors, this type always returns `Err` if an error (fatal or not) was reported. 177 pub type VerifierResult<T> = Result<T, VerifierErrors>; 178 179 /// List of verifier errors. 180 #[derive(Debug, Default, PartialEq, Eq, Clone)] 181 pub struct VerifierErrors(pub Vec<VerifierError>); 182 183 // This is manually implementing Error and Display instead of using thiserror to reduce the amount 184 // of dependencies used by Cranelift. 185 impl std::error::Error for VerifierErrors {} 186 187 impl VerifierErrors { 188 /// Return a new `VerifierErrors` struct. 189 #[inline] 190 pub fn new() -> Self { 191 Self(Vec::new()) 192 } 193 194 /// Return whether no errors were reported. 195 #[inline] 196 pub fn is_empty(&self) -> bool { 197 self.0.is_empty() 198 } 199 200 /// Return whether one or more errors were reported. 201 #[inline] 202 pub fn has_error(&self) -> bool { 203 !self.0.is_empty() 204 } 205 206 /// Return a `VerifierStepResult` that is fatal if at least one error was reported, 207 /// and non-fatal otherwise. 208 #[inline] 209 pub fn as_result(&self) -> VerifierStepResult<()> { 210 if self.is_empty() { 211 Ok(()) 212 } else { 213 Err(()) 214 } 215 } 216 217 /// Report an error, adding it to the list of errors. 218 pub fn report(&mut self, error: impl Into<VerifierError>) { 219 self.0.push(error.into()); 220 } 221 222 /// Report a fatal error and return `Err`. 223 pub fn fatal(&mut self, error: impl Into<VerifierError>) -> VerifierStepResult<()> { 224 self.report(error); 225 Err(()) 226 } 227 228 /// Report a non-fatal error and return `Ok`. 229 pub fn nonfatal(&mut self, error: impl Into<VerifierError>) -> VerifierStepResult<()> { 230 self.report(error); 231 Ok(()) 232 } 233 } 234 235 impl From<Vec<VerifierError>> for VerifierErrors { 236 fn from(v: Vec<VerifierError>) -> Self { 237 Self(v) 238 } 239 } 240 241 impl Into<Vec<VerifierError>> for VerifierErrors { 242 fn into(self) -> Vec<VerifierError> { 243 self.0 244 } 245 } 246 247 impl Into<VerifierResult<()>> for VerifierErrors { 248 fn into(self) -> VerifierResult<()> { 249 if self.is_empty() { 250 Ok(()) 251 } else { 252 Err(self) 253 } 254 } 255 } 256 257 impl Display for VerifierErrors { 258 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 259 for err in &self.0 { 260 writeln!(f, "- {}", err)?; 261 } 262 Ok(()) 263 } 264 } 265 266 /// Verify `func`. 267 pub fn verify_function<'a, FOI: Into<FlagsOrIsa<'a>>>( 268 func: &Function, 269 fisa: FOI, 270 ) -> VerifierResult<()> { 271 let _tt = timing::verifier(); 272 let mut errors = VerifierErrors::default(); 273 let verifier = Verifier::new(func, fisa.into()); 274 let result = verifier.run(&mut errors); 275 if errors.is_empty() { 276 result.unwrap(); 277 Ok(()) 278 } else { 279 Err(errors) 280 } 281 } 282 283 /// Verify `func` after checking the integrity of associated context data structures `cfg` and 284 /// `domtree`. 285 pub fn verify_context<'a, FOI: Into<FlagsOrIsa<'a>>>( 286 func: &Function, 287 cfg: &ControlFlowGraph, 288 domtree: &DominatorTree, 289 fisa: FOI, 290 errors: &mut VerifierErrors, 291 ) -> VerifierStepResult<()> { 292 let _tt = timing::verifier(); 293 let verifier = Verifier::new(func, fisa.into()); 294 if cfg.is_valid() { 295 verifier.cfg_integrity(cfg, errors)?; 296 } 297 if domtree.is_valid() { 298 verifier.domtree_integrity(domtree, errors)?; 299 } 300 verifier.run(errors) 301 } 302 303 struct Verifier<'a> { 304 func: &'a Function, 305 expected_cfg: ControlFlowGraph, 306 expected_domtree: DominatorTree, 307 isa: Option<&'a dyn TargetIsa>, 308 } 309 310 impl<'a> Verifier<'a> { 311 pub fn new(func: &'a Function, fisa: FlagsOrIsa<'a>) -> Self { 312 let expected_cfg = ControlFlowGraph::with_function(func); 313 let expected_domtree = DominatorTree::with_function(func, &expected_cfg); 314 Self { 315 func, 316 expected_cfg, 317 expected_domtree, 318 isa: fisa.isa, 319 } 320 } 321 322 /// Determine a contextual error string for an instruction. 323 #[inline] 324 fn context(&self, inst: Inst) -> String { 325 self.func.dfg.display_inst(inst, self.isa).to_string() 326 } 327 328 // Check for: 329 // - cycles in the global value declarations. 330 // - use of 'vmctx' when no special parameter declares it. 331 fn verify_global_values(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> { 332 let mut cycle_seen = false; 333 let mut seen = SparseSet::new(); 334 335 'gvs: for gv in self.func.global_values.keys() { 336 seen.clear(); 337 seen.insert(gv); 338 339 let mut cur = gv; 340 loop { 341 match self.func.global_values[cur] { 342 ir::GlobalValueData::Load { base, .. } 343 | ir::GlobalValueData::IAddImm { base, .. } => { 344 if seen.insert(base).is_some() { 345 if !cycle_seen { 346 errors.report(( 347 gv, 348 format!("global value cycle: {}", DisplayList(seen.as_slice())), 349 )); 350 // ensures we don't report the cycle multiple times 351 cycle_seen = true; 352 } 353 continue 'gvs; 354 } 355 356 cur = base; 357 } 358 _ => break, 359 } 360 } 361 362 match self.func.global_values[gv] { 363 ir::GlobalValueData::VMContext { .. } => { 364 if self 365 .func 366 .special_param(ir::ArgumentPurpose::VMContext) 367 .is_none() 368 { 369 errors.report((gv, format!("undeclared vmctx reference {}", gv))); 370 } 371 } 372 ir::GlobalValueData::IAddImm { 373 base, global_type, .. 374 } => { 375 if !global_type.is_int() { 376 errors.report(( 377 gv, 378 format!("iadd_imm global value with non-int type {}", global_type), 379 )); 380 } else if let Some(isa) = self.isa { 381 let base_type = self.func.global_values[base].global_type(isa); 382 if global_type != base_type { 383 errors.report(( 384 gv, 385 format!( 386 "iadd_imm type {} differs from operand type {}", 387 global_type, base_type 388 ), 389 )); 390 } 391 } 392 } 393 ir::GlobalValueData::Load { base, .. } => { 394 if let Some(isa) = self.isa { 395 let base_type = self.func.global_values[base].global_type(isa); 396 let pointer_type = isa.pointer_type(); 397 if base_type != pointer_type { 398 errors.report(( 399 gv, 400 format!( 401 "base {} has type {}, which is not the pointer type {}", 402 base, base_type, pointer_type 403 ), 404 )); 405 } 406 } 407 } 408 _ => {} 409 } 410 } 411 412 // Invalid global values shouldn't stop us from verifying the rest of the function 413 Ok(()) 414 } 415 416 fn verify_heaps(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> { 417 if let Some(isa) = self.isa { 418 for (heap, heap_data) in &self.func.heaps { 419 let base = heap_data.base; 420 if !self.func.global_values.is_valid(base) { 421 return errors.nonfatal((heap, format!("invalid base global value {}", base))); 422 } 423 424 let pointer_type = isa.pointer_type(); 425 let base_type = self.func.global_values[base].global_type(isa); 426 if base_type != pointer_type { 427 errors.report(( 428 heap, 429 format!( 430 "heap base has type {}, which is not the pointer type {}", 431 base_type, pointer_type 432 ), 433 )); 434 } 435 436 if let ir::HeapStyle::Dynamic { bound_gv, .. } = heap_data.style { 437 if !self.func.global_values.is_valid(bound_gv) { 438 return errors 439 .nonfatal((heap, format!("invalid bound global value {}", bound_gv))); 440 } 441 442 let bound_type = self.func.global_values[bound_gv].global_type(isa); 443 if pointer_type != bound_type { 444 errors.report(( 445 heap, 446 format!( 447 "heap pointer type {} differs from the type of its bound, {}", 448 pointer_type, bound_type 449 ), 450 )); 451 } 452 } 453 } 454 } 455 456 Ok(()) 457 } 458 459 fn verify_tables(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> { 460 if let Some(isa) = self.isa { 461 for (table, table_data) in &self.func.tables { 462 let base = table_data.base_gv; 463 if !self.func.global_values.is_valid(base) { 464 return errors.nonfatal((table, format!("invalid base global value {}", base))); 465 } 466 467 let pointer_type = isa.pointer_type(); 468 let base_type = self.func.global_values[base].global_type(isa); 469 if base_type != pointer_type { 470 errors.report(( 471 table, 472 format!( 473 "table base has type {}, which is not the pointer type {}", 474 base_type, pointer_type 475 ), 476 )); 477 } 478 479 let bound_gv = table_data.bound_gv; 480 if !self.func.global_values.is_valid(bound_gv) { 481 return errors 482 .nonfatal((table, format!("invalid bound global value {}", bound_gv))); 483 } 484 485 let index_type = table_data.index_type; 486 let bound_type = self.func.global_values[bound_gv].global_type(isa); 487 if index_type != bound_type { 488 errors.report(( 489 table, 490 format!( 491 "table index type {} differs from the type of its bound, {}", 492 index_type, bound_type 493 ), 494 )); 495 } 496 } 497 } 498 499 Ok(()) 500 } 501 502 fn verify_jump_tables(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> { 503 for (jt, jt_data) in &self.func.jump_tables { 504 for &block in jt_data.iter() { 505 self.verify_block(jt, block, errors)?; 506 } 507 } 508 Ok(()) 509 } 510 511 /// Check that the given block can be encoded as a BB, by checking that only 512 /// branching instructions are ending the block. 513 fn encodable_as_bb(&self, block: Block, errors: &mut VerifierErrors) -> VerifierStepResult<()> { 514 match self.func.is_block_basic(block) { 515 Ok(()) => Ok(()), 516 Err((inst, message)) => errors.fatal((inst, self.context(inst), message)), 517 } 518 } 519 520 fn block_integrity( 521 &self, 522 block: Block, 523 inst: Inst, 524 errors: &mut VerifierErrors, 525 ) -> VerifierStepResult<()> { 526 let is_terminator = self.func.dfg[inst].opcode().is_terminator(); 527 let is_last_inst = self.func.layout.last_inst(block) == Some(inst); 528 529 if is_terminator && !is_last_inst { 530 // Terminating instructions only occur at the end of blocks. 531 return errors.fatal(( 532 inst, 533 self.context(inst), 534 format!( 535 "a terminator instruction was encountered before the end of {}", 536 block 537 ), 538 )); 539 } 540 if is_last_inst && !is_terminator { 541 return errors.fatal((block, "block does not end in a terminator instruction")); 542 } 543 544 // Instructions belong to the correct block. 545 let inst_block = self.func.layout.inst_block(inst); 546 if inst_block != Some(block) { 547 return errors.fatal(( 548 inst, 549 self.context(inst), 550 format!("should belong to {} not {:?}", block, inst_block), 551 )); 552 } 553 554 // Parameters belong to the correct block. 555 for &arg in self.func.dfg.block_params(block) { 556 match self.func.dfg.value_def(arg) { 557 ValueDef::Param(arg_block, _) => { 558 if block != arg_block { 559 return errors.fatal((arg, format!("does not belong to {}", block))); 560 } 561 } 562 _ => { 563 return errors.fatal((arg, "expected an argument, found a result")); 564 } 565 } 566 } 567 568 Ok(()) 569 } 570 571 fn instruction_integrity( 572 &self, 573 inst: Inst, 574 errors: &mut VerifierErrors, 575 ) -> VerifierStepResult<()> { 576 let inst_data = &self.func.dfg[inst]; 577 let dfg = &self.func.dfg; 578 579 // The instruction format matches the opcode 580 if inst_data.opcode().format() != InstructionFormat::from(inst_data) { 581 return errors.fatal(( 582 inst, 583 self.context(inst), 584 "instruction opcode doesn't match instruction format", 585 )); 586 } 587 588 let num_fixed_results = inst_data.opcode().constraints().num_fixed_results(); 589 // var_results is 0 if we aren't a call instruction 590 let var_results = dfg 591 .call_signature(inst) 592 .map_or(0, |sig| dfg.signatures[sig].returns.len()); 593 let total_results = num_fixed_results + var_results; 594 595 // All result values for multi-valued instructions are created 596 let got_results = dfg.inst_results(inst).len(); 597 if got_results != total_results { 598 return errors.fatal(( 599 inst, 600 self.context(inst), 601 format!( 602 "expected {} result values, found {}", 603 total_results, got_results, 604 ), 605 )); 606 } 607 608 self.verify_entity_references(inst, errors) 609 } 610 611 fn verify_entity_references( 612 &self, 613 inst: Inst, 614 errors: &mut VerifierErrors, 615 ) -> VerifierStepResult<()> { 616 use crate::ir::instructions::InstructionData::*; 617 618 for &arg in self.func.dfg.inst_args(inst) { 619 self.verify_inst_arg(inst, arg, errors)?; 620 621 // All used values must be attached to something. 622 let original = self.func.dfg.resolve_aliases(arg); 623 if !self.func.dfg.value_is_attached(original) { 624 errors.report(( 625 inst, 626 self.context(inst), 627 format!("argument {} -> {} is not attached", arg, original), 628 )); 629 } 630 } 631 632 for &res in self.func.dfg.inst_results(inst) { 633 self.verify_inst_result(inst, res, errors)?; 634 } 635 636 match self.func.dfg[inst] { 637 MultiAry { ref args, .. } => { 638 self.verify_value_list(inst, args, errors)?; 639 } 640 Jump { 641 destination, 642 ref args, 643 .. 644 } 645 | Branch { 646 destination, 647 ref args, 648 .. 649 } 650 | BranchInt { 651 destination, 652 ref args, 653 .. 654 } 655 | BranchFloat { 656 destination, 657 ref args, 658 .. 659 } 660 | BranchIcmp { 661 destination, 662 ref args, 663 .. 664 } => { 665 self.verify_block(inst, destination, errors)?; 666 self.verify_value_list(inst, args, errors)?; 667 } 668 BranchTable { 669 table, destination, .. 670 } => { 671 self.verify_block(inst, destination, errors)?; 672 self.verify_jump_table(inst, table, errors)?; 673 } 674 BranchTableBase { table, .. } 675 | BranchTableEntry { table, .. } 676 | IndirectJump { table, .. } => { 677 self.verify_jump_table(inst, table, errors)?; 678 } 679 Call { 680 func_ref, ref args, .. 681 } => { 682 self.verify_func_ref(inst, func_ref, errors)?; 683 self.verify_value_list(inst, args, errors)?; 684 } 685 CallIndirect { 686 sig_ref, ref args, .. 687 } => { 688 self.verify_sig_ref(inst, sig_ref, errors)?; 689 self.verify_value_list(inst, args, errors)?; 690 } 691 FuncAddr { func_ref, .. } => { 692 self.verify_func_ref(inst, func_ref, errors)?; 693 } 694 StackLoad { stack_slot, .. } | StackStore { stack_slot, .. } => { 695 self.verify_stack_slot(inst, stack_slot, errors)?; 696 } 697 UnaryGlobalValue { global_value, .. } => { 698 self.verify_global_value(inst, global_value, errors)?; 699 } 700 HeapAddr { heap, .. } => { 701 self.verify_heap(inst, heap, errors)?; 702 } 703 TableAddr { table, .. } => { 704 self.verify_table(inst, table, errors)?; 705 } 706 RegSpill { dst, .. } => { 707 self.verify_stack_slot(inst, dst, errors)?; 708 } 709 RegFill { src, .. } => { 710 self.verify_stack_slot(inst, src, errors)?; 711 } 712 LoadComplex { ref args, .. } => { 713 self.verify_value_list(inst, args, errors)?; 714 } 715 StoreComplex { ref args, .. } => { 716 self.verify_value_list(inst, args, errors)?; 717 } 718 719 NullAry { 720 opcode: Opcode::GetPinnedReg, 721 } 722 | Unary { 723 opcode: Opcode::SetPinnedReg, 724 .. 725 } => { 726 if let Some(isa) = &self.isa { 727 if !isa.flags().enable_pinned_reg() { 728 return errors.fatal(( 729 inst, 730 self.context(inst), 731 "GetPinnedReg/SetPinnedReg cannot be used without enable_pinned_reg", 732 )); 733 } 734 } else { 735 return errors.fatal(( 736 inst, 737 self.context(inst), 738 "GetPinnedReg/SetPinnedReg need an ISA!", 739 )); 740 } 741 } 742 Unary { 743 opcode: Opcode::Bitcast, 744 arg, 745 } => { 746 self.verify_bitcast(inst, arg, errors)?; 747 } 748 UnaryConst { 749 opcode: Opcode::Vconst, 750 constant_handle, 751 .. 752 } => { 753 self.verify_constant_size(inst, constant_handle, errors)?; 754 } 755 756 // Exhaustive list so we can't forget to add new formats 757 AtomicCas { .. } 758 | AtomicRmw { .. } 759 | LoadNoOffset { .. } 760 | StoreNoOffset { .. } 761 | Unary { .. } 762 | UnaryConst { .. } 763 | UnaryImm { .. } 764 | UnaryIeee32 { .. } 765 | UnaryIeee64 { .. } 766 | UnaryBool { .. } 767 | Binary { .. } 768 | BinaryImm8 { .. } 769 | BinaryImm64 { .. } 770 | Ternary { .. } 771 | TernaryImm8 { .. } 772 | Shuffle { .. } 773 | IntCompare { .. } 774 | IntCompareImm { .. } 775 | IntCond { .. } 776 | FloatCompare { .. } 777 | FloatCond { .. } 778 | IntSelect { .. } 779 | Load { .. } 780 | Store { .. } 781 | RegMove { .. } 782 | CopySpecial { .. } 783 | CopyToSsa { .. } 784 | Trap { .. } 785 | CondTrap { .. } 786 | IntCondTrap { .. } 787 | FloatCondTrap { .. } 788 | NullAry { .. } => {} 789 } 790 791 Ok(()) 792 } 793 794 fn verify_block( 795 &self, 796 loc: impl Into<AnyEntity>, 797 e: Block, 798 errors: &mut VerifierErrors, 799 ) -> VerifierStepResult<()> { 800 if !self.func.dfg.block_is_valid(e) || !self.func.layout.is_block_inserted(e) { 801 return errors.fatal((loc, format!("invalid block reference {}", e))); 802 } 803 if let Some(entry_block) = self.func.layout.entry_block() { 804 if e == entry_block { 805 return errors.fatal((loc, format!("invalid reference to entry block {}", e))); 806 } 807 } 808 Ok(()) 809 } 810 811 fn verify_sig_ref( 812 &self, 813 inst: Inst, 814 s: SigRef, 815 errors: &mut VerifierErrors, 816 ) -> VerifierStepResult<()> { 817 if !self.func.dfg.signatures.is_valid(s) { 818 errors.fatal(( 819 inst, 820 self.context(inst), 821 format!("invalid signature reference {}", s), 822 )) 823 } else { 824 Ok(()) 825 } 826 } 827 828 fn verify_func_ref( 829 &self, 830 inst: Inst, 831 f: FuncRef, 832 errors: &mut VerifierErrors, 833 ) -> VerifierStepResult<()> { 834 if !self.func.dfg.ext_funcs.is_valid(f) { 835 errors.nonfatal(( 836 inst, 837 self.context(inst), 838 format!("invalid function reference {}", f), 839 )) 840 } else { 841 Ok(()) 842 } 843 } 844 845 fn verify_stack_slot( 846 &self, 847 inst: Inst, 848 ss: StackSlot, 849 errors: &mut VerifierErrors, 850 ) -> VerifierStepResult<()> { 851 if !self.func.stack_slots.is_valid(ss) { 852 errors.nonfatal(( 853 inst, 854 self.context(inst), 855 format!("invalid stack slot {}", ss), 856 )) 857 } else { 858 Ok(()) 859 } 860 } 861 862 fn verify_global_value( 863 &self, 864 inst: Inst, 865 gv: GlobalValue, 866 errors: &mut VerifierErrors, 867 ) -> VerifierStepResult<()> { 868 if !self.func.global_values.is_valid(gv) { 869 errors.nonfatal(( 870 inst, 871 self.context(inst), 872 format!("invalid global value {}", gv), 873 )) 874 } else { 875 Ok(()) 876 } 877 } 878 879 fn verify_heap( 880 &self, 881 inst: Inst, 882 heap: ir::Heap, 883 errors: &mut VerifierErrors, 884 ) -> VerifierStepResult<()> { 885 if !self.func.heaps.is_valid(heap) { 886 errors.nonfatal((inst, self.context(inst), format!("invalid heap {}", heap))) 887 } else { 888 Ok(()) 889 } 890 } 891 892 fn verify_table( 893 &self, 894 inst: Inst, 895 table: ir::Table, 896 errors: &mut VerifierErrors, 897 ) -> VerifierStepResult<()> { 898 if !self.func.tables.is_valid(table) { 899 errors.nonfatal((inst, self.context(inst), format!("invalid table {}", table))) 900 } else { 901 Ok(()) 902 } 903 } 904 905 fn verify_value_list( 906 &self, 907 inst: Inst, 908 l: &ValueList, 909 errors: &mut VerifierErrors, 910 ) -> VerifierStepResult<()> { 911 if !l.is_valid(&self.func.dfg.value_lists) { 912 errors.nonfatal(( 913 inst, 914 self.context(inst), 915 format!("invalid value list reference {:?}", l), 916 )) 917 } else { 918 Ok(()) 919 } 920 } 921 922 fn verify_jump_table( 923 &self, 924 inst: Inst, 925 j: JumpTable, 926 errors: &mut VerifierErrors, 927 ) -> VerifierStepResult<()> { 928 if !self.func.jump_tables.is_valid(j) { 929 errors.nonfatal(( 930 inst, 931 self.context(inst), 932 format!("invalid jump table reference {}", j), 933 )) 934 } else { 935 Ok(()) 936 } 937 } 938 939 fn verify_value( 940 &self, 941 loc_inst: Inst, 942 v: Value, 943 errors: &mut VerifierErrors, 944 ) -> VerifierStepResult<()> { 945 let dfg = &self.func.dfg; 946 if !dfg.value_is_valid(v) { 947 errors.nonfatal(( 948 loc_inst, 949 self.context(loc_inst), 950 format!("invalid value reference {}", v), 951 )) 952 } else { 953 Ok(()) 954 } 955 } 956 957 fn verify_inst_arg( 958 &self, 959 loc_inst: Inst, 960 v: Value, 961 errors: &mut VerifierErrors, 962 ) -> VerifierStepResult<()> { 963 self.verify_value(loc_inst, v, errors)?; 964 965 let dfg = &self.func.dfg; 966 let loc_block = self.func.layout.pp_block(loc_inst); 967 let is_reachable = self.expected_domtree.is_reachable(loc_block); 968 969 // SSA form 970 match dfg.value_def(v) { 971 ValueDef::Result(def_inst, _) => { 972 // Value is defined by an instruction that exists. 973 if !dfg.inst_is_valid(def_inst) { 974 return errors.fatal(( 975 loc_inst, 976 self.context(loc_inst), 977 format!("{} is defined by invalid instruction {}", v, def_inst), 978 )); 979 } 980 // Defining instruction is inserted in a block. 981 if self.func.layout.inst_block(def_inst) == None { 982 return errors.fatal(( 983 loc_inst, 984 self.context(loc_inst), 985 format!("{} is defined by {} which has no block", v, def_inst), 986 )); 987 } 988 // Defining instruction dominates the instruction that uses the value. 989 if is_reachable { 990 if !self 991 .expected_domtree 992 .dominates(def_inst, loc_inst, &self.func.layout) 993 { 994 return errors.fatal(( 995 loc_inst, 996 self.context(loc_inst), 997 format!("uses value {} from non-dominating {}", v, def_inst), 998 )); 999 } 1000 if def_inst == loc_inst { 1001 return errors.fatal(( 1002 loc_inst, 1003 self.context(loc_inst), 1004 format!("uses value {} from itself", v), 1005 )); 1006 } 1007 } 1008 } 1009 ValueDef::Param(block, _) => { 1010 // Value is defined by an existing block. 1011 if !dfg.block_is_valid(block) { 1012 return errors.fatal(( 1013 loc_inst, 1014 self.context(loc_inst), 1015 format!("{} is defined by invalid block {}", v, block), 1016 )); 1017 } 1018 // Defining block is inserted in the layout 1019 if !self.func.layout.is_block_inserted(block) { 1020 return errors.fatal(( 1021 loc_inst, 1022 self.context(loc_inst), 1023 format!("{} is defined by {} which is not in the layout", v, block), 1024 )); 1025 } 1026 // The defining block dominates the instruction using this value. 1027 if is_reachable 1028 && !self 1029 .expected_domtree 1030 .dominates(block, loc_inst, &self.func.layout) 1031 { 1032 return errors.fatal(( 1033 loc_inst, 1034 self.context(loc_inst), 1035 format!("uses value arg from non-dominating {}", block), 1036 )); 1037 } 1038 } 1039 } 1040 Ok(()) 1041 } 1042 1043 fn verify_inst_result( 1044 &self, 1045 loc_inst: Inst, 1046 v: Value, 1047 errors: &mut VerifierErrors, 1048 ) -> VerifierStepResult<()> { 1049 self.verify_value(loc_inst, v, errors)?; 1050 1051 match self.func.dfg.value_def(v) { 1052 ValueDef::Result(def_inst, _) => { 1053 if def_inst != loc_inst { 1054 errors.fatal(( 1055 loc_inst, 1056 self.context(loc_inst), 1057 format!("instruction result {} is not defined by the instruction", v), 1058 )) 1059 } else { 1060 Ok(()) 1061 } 1062 } 1063 ValueDef::Param(_, _) => errors.fatal(( 1064 loc_inst, 1065 self.context(loc_inst), 1066 format!("instruction result {} is not defined by the instruction", v), 1067 )), 1068 } 1069 } 1070 1071 fn verify_bitcast( 1072 &self, 1073 inst: Inst, 1074 arg: Value, 1075 errors: &mut VerifierErrors, 1076 ) -> VerifierStepResult<()> { 1077 let typ = self.func.dfg.ctrl_typevar(inst); 1078 let value_type = self.func.dfg.value_type(arg); 1079 1080 if typ.lane_bits() < value_type.lane_bits() { 1081 errors.fatal(( 1082 inst, 1083 format!( 1084 "The bitcast argument {} doesn't fit in a type of {} bits", 1085 arg, 1086 typ.lane_bits() 1087 ), 1088 )) 1089 } else { 1090 Ok(()) 1091 } 1092 } 1093 1094 fn verify_constant_size( 1095 &self, 1096 inst: Inst, 1097 constant: Constant, 1098 errors: &mut VerifierErrors, 1099 ) -> VerifierStepResult<()> { 1100 let type_size = self.func.dfg.ctrl_typevar(inst).bytes() as usize; 1101 let constant_size = self.func.dfg.constants.get(constant).len(); 1102 if type_size != constant_size { 1103 errors.fatal(( 1104 inst, 1105 format!( 1106 "The instruction expects {} to have a size of {} bytes but it has {}", 1107 constant, type_size, constant_size 1108 ), 1109 )) 1110 } else { 1111 Ok(()) 1112 } 1113 } 1114 1115 fn domtree_integrity( 1116 &self, 1117 domtree: &DominatorTree, 1118 errors: &mut VerifierErrors, 1119 ) -> VerifierStepResult<()> { 1120 // We consider two `DominatorTree`s to be equal if they return the same immediate 1121 // dominator for each block. Therefore the current domtree is valid if it matches the freshly 1122 // computed one. 1123 for block in self.func.layout.blocks() { 1124 let expected = self.expected_domtree.idom(block); 1125 let got = domtree.idom(block); 1126 if got != expected { 1127 return errors.fatal(( 1128 block, 1129 format!( 1130 "invalid domtree, expected idom({}) = {:?}, got {:?}", 1131 block, expected, got 1132 ), 1133 )); 1134 } 1135 } 1136 // We also verify if the postorder defined by `DominatorTree` is sane 1137 if domtree.cfg_postorder().len() != self.expected_domtree.cfg_postorder().len() { 1138 return errors.fatal(( 1139 AnyEntity::Function, 1140 "incorrect number of Blocks in postorder traversal", 1141 )); 1142 } 1143 for (index, (&test_block, &true_block)) in domtree 1144 .cfg_postorder() 1145 .iter() 1146 .zip(self.expected_domtree.cfg_postorder().iter()) 1147 .enumerate() 1148 { 1149 if test_block != true_block { 1150 return errors.fatal(( 1151 test_block, 1152 format!( 1153 "invalid domtree, postorder block number {} should be {}, got {}", 1154 index, true_block, test_block 1155 ), 1156 )); 1157 } 1158 } 1159 // We verify rpo_cmp on pairs of adjacent blocks in the postorder 1160 for (&prev_block, &next_block) in domtree.cfg_postorder().iter().adjacent_pairs() { 1161 if self 1162 .expected_domtree 1163 .rpo_cmp(prev_block, next_block, &self.func.layout) 1164 != Ordering::Greater 1165 { 1166 return errors.fatal(( 1167 next_block, 1168 format!( 1169 "invalid domtree, rpo_cmp does not says {} is greater than {}", 1170 prev_block, next_block 1171 ), 1172 )); 1173 } 1174 } 1175 Ok(()) 1176 } 1177 1178 fn typecheck_entry_block_params(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> { 1179 if let Some(block) = self.func.layout.entry_block() { 1180 let expected_types = &self.func.signature.params; 1181 let block_param_count = self.func.dfg.num_block_params(block); 1182 1183 if block_param_count != expected_types.len() { 1184 return errors.fatal(( 1185 block, 1186 format!( 1187 "entry block parameters ({}) must match function signature ({})", 1188 block_param_count, 1189 expected_types.len() 1190 ), 1191 )); 1192 } 1193 1194 for (i, &arg) in self.func.dfg.block_params(block).iter().enumerate() { 1195 let arg_type = self.func.dfg.value_type(arg); 1196 if arg_type != expected_types[i].value_type { 1197 errors.report(( 1198 block, 1199 format!( 1200 "entry block parameter {} expected to have type {}, got {}", 1201 i, expected_types[i], arg_type 1202 ), 1203 )); 1204 } 1205 } 1206 } 1207 1208 errors.as_result() 1209 } 1210 1211 fn typecheck(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()> { 1212 let inst_data = &self.func.dfg[inst]; 1213 let constraints = inst_data.opcode().constraints(); 1214 1215 let ctrl_type = if let Some(value_typeset) = constraints.ctrl_typeset() { 1216 // For polymorphic opcodes, determine the controlling type variable first. 1217 let ctrl_type = self.func.dfg.ctrl_typevar(inst); 1218 1219 if !value_typeset.contains(ctrl_type) { 1220 errors.report(( 1221 inst, 1222 self.context(inst), 1223 format!("has an invalid controlling type {}", ctrl_type), 1224 )); 1225 } 1226 1227 ctrl_type 1228 } else { 1229 // Non-polymorphic instructions don't check the controlling type variable, so `Option` 1230 // is unnecessary and we can just make it `INVALID`. 1231 types::INVALID 1232 }; 1233 1234 // Typechecking instructions is never fatal 1235 let _ = self.typecheck_results(inst, ctrl_type, errors); 1236 let _ = self.typecheck_fixed_args(inst, ctrl_type, errors); 1237 let _ = self.typecheck_variable_args(inst, errors); 1238 let _ = self.typecheck_return(inst, errors); 1239 let _ = self.typecheck_special(inst, ctrl_type, errors); 1240 1241 // Misuses of copy_nop instructions are fatal 1242 self.typecheck_copy_nop(inst, errors)?; 1243 1244 Ok(()) 1245 } 1246 1247 fn typecheck_results( 1248 &self, 1249 inst: Inst, 1250 ctrl_type: Type, 1251 errors: &mut VerifierErrors, 1252 ) -> VerifierStepResult<()> { 1253 let mut i = 0; 1254 for &result in self.func.dfg.inst_results(inst) { 1255 let result_type = self.func.dfg.value_type(result); 1256 let expected_type = self.func.dfg.compute_result_type(inst, i, ctrl_type); 1257 if let Some(expected_type) = expected_type { 1258 if result_type != expected_type { 1259 errors.report(( 1260 inst, 1261 self.context(inst), 1262 format!( 1263 "expected result {} ({}) to have type {}, found {}", 1264 i, result, expected_type, result_type 1265 ), 1266 )); 1267 } 1268 } else { 1269 return errors.nonfatal(( 1270 inst, 1271 self.context(inst), 1272 "has more result values than expected", 1273 )); 1274 } 1275 i += 1; 1276 } 1277 1278 // There aren't any more result types left. 1279 if self.func.dfg.compute_result_type(inst, i, ctrl_type) != None { 1280 return errors.nonfatal(( 1281 inst, 1282 self.context(inst), 1283 "has fewer result values than expected", 1284 )); 1285 } 1286 Ok(()) 1287 } 1288 1289 fn typecheck_fixed_args( 1290 &self, 1291 inst: Inst, 1292 ctrl_type: Type, 1293 errors: &mut VerifierErrors, 1294 ) -> VerifierStepResult<()> { 1295 let constraints = self.func.dfg[inst].opcode().constraints(); 1296 1297 for (i, &arg) in self.func.dfg.inst_fixed_args(inst).iter().enumerate() { 1298 let arg_type = self.func.dfg.value_type(arg); 1299 match constraints.value_argument_constraint(i, ctrl_type) { 1300 ResolvedConstraint::Bound(expected_type) => { 1301 if arg_type != expected_type { 1302 errors.report(( 1303 inst, 1304 self.context(inst), 1305 format!( 1306 "arg {} ({}) has type {}, expected {}", 1307 i, arg, arg_type, expected_type 1308 ), 1309 )); 1310 } 1311 } 1312 ResolvedConstraint::Free(type_set) => { 1313 if !type_set.contains(arg_type) { 1314 errors.report(( 1315 inst, 1316 self.context(inst), 1317 format!( 1318 "arg {} ({}) with type {} failed to satisfy type set {:?}", 1319 i, arg, arg_type, type_set 1320 ), 1321 )); 1322 } 1323 } 1324 } 1325 } 1326 Ok(()) 1327 } 1328 1329 fn typecheck_variable_args( 1330 &self, 1331 inst: Inst, 1332 errors: &mut VerifierErrors, 1333 ) -> VerifierStepResult<()> { 1334 match self.func.dfg.analyze_branch(inst) { 1335 BranchInfo::SingleDest(block, _) => { 1336 let iter = self 1337 .func 1338 .dfg 1339 .block_params(block) 1340 .iter() 1341 .map(|&v| self.func.dfg.value_type(v)); 1342 self.typecheck_variable_args_iterator(inst, iter, errors)?; 1343 } 1344 BranchInfo::Table(table, block) => { 1345 if let Some(block) = block { 1346 let arg_count = self.func.dfg.num_block_params(block); 1347 if arg_count != 0 { 1348 return errors.nonfatal(( 1349 inst, 1350 self.context(inst), 1351 format!( 1352 "takes no arguments, but had target {} with {} arguments", 1353 block, arg_count, 1354 ), 1355 )); 1356 } 1357 } 1358 for block in self.func.jump_tables[table].iter() { 1359 let arg_count = self.func.dfg.num_block_params(*block); 1360 if arg_count != 0 { 1361 return errors.nonfatal(( 1362 inst, 1363 self.context(inst), 1364 format!( 1365 "takes no arguments, but had target {} with {} arguments", 1366 block, arg_count, 1367 ), 1368 )); 1369 } 1370 } 1371 } 1372 BranchInfo::NotABranch => {} 1373 } 1374 1375 match self.func.dfg[inst].analyze_call(&self.func.dfg.value_lists) { 1376 CallInfo::Direct(func_ref, _) => { 1377 let sig_ref = self.func.dfg.ext_funcs[func_ref].signature; 1378 let arg_types = self.func.dfg.signatures[sig_ref] 1379 .params 1380 .iter() 1381 .map(|a| a.value_type); 1382 self.typecheck_variable_args_iterator(inst, arg_types, errors)?; 1383 self.check_outgoing_args(inst, sig_ref, errors)?; 1384 } 1385 CallInfo::Indirect(sig_ref, _) => { 1386 let arg_types = self.func.dfg.signatures[sig_ref] 1387 .params 1388 .iter() 1389 .map(|a| a.value_type); 1390 self.typecheck_variable_args_iterator(inst, arg_types, errors)?; 1391 self.check_outgoing_args(inst, sig_ref, errors)?; 1392 } 1393 CallInfo::NotACall => {} 1394 } 1395 Ok(()) 1396 } 1397 1398 fn typecheck_variable_args_iterator<I: Iterator<Item = Type>>( 1399 &self, 1400 inst: Inst, 1401 iter: I, 1402 errors: &mut VerifierErrors, 1403 ) -> VerifierStepResult<()> { 1404 let variable_args = self.func.dfg.inst_variable_args(inst); 1405 let mut i = 0; 1406 1407 for expected_type in iter { 1408 if i >= variable_args.len() { 1409 // Result count mismatch handled below, we want the full argument count first though 1410 i += 1; 1411 continue; 1412 } 1413 let arg = variable_args[i]; 1414 let arg_type = self.func.dfg.value_type(arg); 1415 if expected_type != arg_type { 1416 errors.report(( 1417 inst, 1418 self.context(inst), 1419 format!( 1420 "arg {} ({}) has type {}, expected {}", 1421 i, variable_args[i], arg_type, expected_type 1422 ), 1423 )); 1424 } 1425 i += 1; 1426 } 1427 if i != variable_args.len() { 1428 return errors.nonfatal(( 1429 inst, 1430 self.context(inst), 1431 format!( 1432 "mismatched argument count for `{}`: got {}, expected {}", 1433 self.func.dfg.display_inst(inst, None), 1434 variable_args.len(), 1435 i, 1436 ), 1437 )); 1438 } 1439 Ok(()) 1440 } 1441 1442 /// Check the locations assigned to outgoing call arguments. 1443 /// 1444 /// When a signature has been legalized, all values passed as outgoing arguments on the stack 1445 /// must be assigned to a matching `OutgoingArg` stack slot. 1446 fn check_outgoing_args( 1447 &self, 1448 inst: Inst, 1449 sig_ref: SigRef, 1450 errors: &mut VerifierErrors, 1451 ) -> VerifierStepResult<()> { 1452 let sig = &self.func.dfg.signatures[sig_ref]; 1453 1454 let args = self.func.dfg.inst_variable_args(inst); 1455 let expected_args = &sig.params[..]; 1456 1457 for (&arg, &abi) in args.iter().zip(expected_args) { 1458 // Value types have already been checked by `typecheck_variable_args_iterator()`. 1459 if let ArgumentLoc::Stack(offset) = abi.location { 1460 let arg_loc = self.func.locations[arg]; 1461 if let ValueLoc::Stack(ss) = arg_loc { 1462 // Argument value is assigned to a stack slot as expected. 1463 self.verify_stack_slot(inst, ss, errors)?; 1464 let slot = &self.func.stack_slots[ss]; 1465 if slot.kind != StackSlotKind::OutgoingArg { 1466 return errors.fatal(( 1467 inst, 1468 self.context(inst), 1469 format!( 1470 "Outgoing stack argument {} in wrong stack slot: {} = {}", 1471 arg, ss, slot, 1472 ), 1473 )); 1474 } 1475 if slot.offset != Some(offset) { 1476 return errors.fatal(( 1477 inst, 1478 self.context(inst), 1479 format!( 1480 "Outgoing stack argument {} should have offset {}: {} = {}", 1481 arg, offset, ss, slot, 1482 ), 1483 )); 1484 } 1485 if abi.purpose == ArgumentPurpose::StructArgument(slot.size) { 1486 } else if slot.size != abi.value_type.bytes() { 1487 return errors.fatal(( 1488 inst, 1489 self.context(inst), 1490 format!( 1491 "Outgoing stack argument {} wrong size for {}: {} = {}", 1492 arg, abi.value_type, ss, slot, 1493 ), 1494 )); 1495 } 1496 } else { 1497 let reginfo = self.isa.map(|i| i.register_info()); 1498 return errors.fatal(( 1499 inst, 1500 self.context(inst), 1501 format!( 1502 "Outgoing stack argument {} in wrong location: {}", 1503 arg, 1504 arg_loc.display(reginfo.as_ref()) 1505 ), 1506 )); 1507 } 1508 } 1509 } 1510 Ok(()) 1511 } 1512 1513 fn typecheck_return(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()> { 1514 if self.func.dfg[inst].opcode().is_return() { 1515 let args = self.func.dfg.inst_variable_args(inst); 1516 let expected_types = &self.func.signature.returns; 1517 if args.len() != expected_types.len() { 1518 return errors.nonfatal(( 1519 inst, 1520 self.context(inst), 1521 "arguments of return must match function signature", 1522 )); 1523 } 1524 for (i, (&arg, &expected_type)) in args.iter().zip(expected_types).enumerate() { 1525 let arg_type = self.func.dfg.value_type(arg); 1526 if arg_type != expected_type.value_type { 1527 errors.report(( 1528 inst, 1529 self.context(inst), 1530 format!( 1531 "arg {} ({}) has type {}, must match function signature of {}", 1532 i, arg, arg_type, expected_type 1533 ), 1534 )); 1535 } 1536 } 1537 } 1538 Ok(()) 1539 } 1540 1541 // Check special-purpose type constraints that can't be expressed in the normal opcode 1542 // constraints. 1543 fn typecheck_special( 1544 &self, 1545 inst: Inst, 1546 ctrl_type: Type, 1547 errors: &mut VerifierErrors, 1548 ) -> VerifierStepResult<()> { 1549 match self.func.dfg[inst] { 1550 ir::InstructionData::Unary { opcode, arg } => { 1551 let arg_type = self.func.dfg.value_type(arg); 1552 match opcode { 1553 Opcode::Bextend | Opcode::Uextend | Opcode::Sextend | Opcode::Fpromote => { 1554 if arg_type.lane_count() != ctrl_type.lane_count() { 1555 return errors.nonfatal(( 1556 inst, 1557 self.context(inst), 1558 format!( 1559 "input {} and output {} must have same number of lanes", 1560 arg_type, ctrl_type, 1561 ), 1562 )); 1563 } 1564 if arg_type.lane_bits() >= ctrl_type.lane_bits() { 1565 return errors.nonfatal(( 1566 inst, 1567 self.context(inst), 1568 format!( 1569 "input {} must be smaller than output {}", 1570 arg_type, ctrl_type, 1571 ), 1572 )); 1573 } 1574 } 1575 Opcode::Breduce | Opcode::Ireduce | Opcode::Fdemote => { 1576 if arg_type.lane_count() != ctrl_type.lane_count() { 1577 return errors.nonfatal(( 1578 inst, 1579 self.context(inst), 1580 format!( 1581 "input {} and output {} must have same number of lanes", 1582 arg_type, ctrl_type, 1583 ), 1584 )); 1585 } 1586 if arg_type.lane_bits() <= ctrl_type.lane_bits() { 1587 return errors.nonfatal(( 1588 inst, 1589 self.context(inst), 1590 format!( 1591 "input {} must be larger than output {}", 1592 arg_type, ctrl_type, 1593 ), 1594 )); 1595 } 1596 } 1597 _ => {} 1598 } 1599 } 1600 ir::InstructionData::HeapAddr { heap, arg, .. } => { 1601 let index_type = self.func.dfg.value_type(arg); 1602 let heap_index_type = self.func.heaps[heap].index_type; 1603 if index_type != heap_index_type { 1604 return errors.nonfatal(( 1605 inst, 1606 self.context(inst), 1607 format!( 1608 "index type {} differs from heap index type {}", 1609 index_type, heap_index_type, 1610 ), 1611 )); 1612 } 1613 } 1614 ir::InstructionData::TableAddr { table, arg, .. } => { 1615 let index_type = self.func.dfg.value_type(arg); 1616 let table_index_type = self.func.tables[table].index_type; 1617 if index_type != table_index_type { 1618 return errors.nonfatal(( 1619 inst, 1620 self.context(inst), 1621 format!( 1622 "index type {} differs from table index type {}", 1623 index_type, table_index_type, 1624 ), 1625 )); 1626 } 1627 } 1628 ir::InstructionData::UnaryGlobalValue { global_value, .. } => { 1629 if let Some(isa) = self.isa { 1630 let inst_type = self.func.dfg.value_type(self.func.dfg.first_result(inst)); 1631 let global_type = self.func.global_values[global_value].global_type(isa); 1632 if inst_type != global_type { 1633 return errors.nonfatal(( 1634 inst, self.context(inst), 1635 format!( 1636 "global_value instruction with type {} references global value with type {}", 1637 inst_type, global_type 1638 )), 1639 ); 1640 } 1641 } 1642 } 1643 _ => {} 1644 } 1645 Ok(()) 1646 } 1647 1648 fn typecheck_copy_nop( 1649 &self, 1650 inst: Inst, 1651 errors: &mut VerifierErrors, 1652 ) -> VerifierStepResult<()> { 1653 if let InstructionData::Unary { 1654 opcode: Opcode::CopyNop, 1655 arg, 1656 } = self.func.dfg[inst] 1657 { 1658 let dst_vals = self.func.dfg.inst_results(inst); 1659 if dst_vals.len() != 1 { 1660 return errors.fatal(( 1661 inst, 1662 self.context(inst), 1663 "copy_nop must produce exactly one result", 1664 )); 1665 } 1666 let dst_val = dst_vals[0]; 1667 if self.func.dfg.value_type(dst_val) != self.func.dfg.value_type(arg) { 1668 return errors.fatal(( 1669 inst, 1670 self.context(inst), 1671 "copy_nop src and dst types must be the same", 1672 )); 1673 } 1674 let src_loc = self.func.locations[arg]; 1675 let dst_loc = self.func.locations[dst_val]; 1676 let locs_ok = match (src_loc, dst_loc) { 1677 (ValueLoc::Stack(src_slot), ValueLoc::Stack(dst_slot)) => src_slot == dst_slot, 1678 _ => false, 1679 }; 1680 if !locs_ok { 1681 return errors.fatal(( 1682 inst, 1683 self.context(inst), 1684 format!( 1685 "copy_nop must refer to identical stack slots, but found {:?} vs {:?}", 1686 src_loc, dst_loc, 1687 ), 1688 )); 1689 } 1690 } 1691 Ok(()) 1692 } 1693 1694 fn cfg_integrity( 1695 &self, 1696 cfg: &ControlFlowGraph, 1697 errors: &mut VerifierErrors, 1698 ) -> VerifierStepResult<()> { 1699 let mut expected_succs = BTreeSet::<Block>::new(); 1700 let mut got_succs = BTreeSet::<Block>::new(); 1701 let mut expected_preds = BTreeSet::<Inst>::new(); 1702 let mut got_preds = BTreeSet::<Inst>::new(); 1703 1704 for block in self.func.layout.blocks() { 1705 expected_succs.extend(self.expected_cfg.succ_iter(block)); 1706 got_succs.extend(cfg.succ_iter(block)); 1707 1708 let missing_succs: Vec<Block> = 1709 expected_succs.difference(&got_succs).cloned().collect(); 1710 if !missing_succs.is_empty() { 1711 errors.report(( 1712 block, 1713 format!("cfg lacked the following successor(s) {:?}", missing_succs), 1714 )); 1715 continue; 1716 } 1717 1718 let excess_succs: Vec<Block> = got_succs.difference(&expected_succs).cloned().collect(); 1719 if !excess_succs.is_empty() { 1720 errors.report(( 1721 block, 1722 format!("cfg had unexpected successor(s) {:?}", excess_succs), 1723 )); 1724 continue; 1725 } 1726 1727 expected_preds.extend( 1728 self.expected_cfg 1729 .pred_iter(block) 1730 .map(|BlockPredecessor { inst, .. }| inst), 1731 ); 1732 got_preds.extend( 1733 cfg.pred_iter(block) 1734 .map(|BlockPredecessor { inst, .. }| inst), 1735 ); 1736 1737 let missing_preds: Vec<Inst> = expected_preds.difference(&got_preds).cloned().collect(); 1738 if !missing_preds.is_empty() { 1739 errors.report(( 1740 block, 1741 format!( 1742 "cfg lacked the following predecessor(s) {:?}", 1743 missing_preds 1744 ), 1745 )); 1746 continue; 1747 } 1748 1749 let excess_preds: Vec<Inst> = got_preds.difference(&expected_preds).cloned().collect(); 1750 if !excess_preds.is_empty() { 1751 errors.report(( 1752 block, 1753 format!("cfg had unexpected predecessor(s) {:?}", excess_preds), 1754 )); 1755 continue; 1756 } 1757 1758 expected_succs.clear(); 1759 got_succs.clear(); 1760 expected_preds.clear(); 1761 got_preds.clear(); 1762 } 1763 errors.as_result() 1764 } 1765 1766 /// If the verifier has been set up with an ISA, make sure that the recorded encoding for the 1767 /// instruction (if any) matches how the ISA would encode it. 1768 fn verify_encoding(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()> { 1769 // When the encodings table is empty, we don't require any instructions to be encoded. 1770 // 1771 // Once some instructions are encoded, we require all side-effecting instructions to have a 1772 // legal encoding. 1773 if self.func.encodings.is_empty() { 1774 return Ok(()); 1775 } 1776 1777 let isa = match self.isa { 1778 Some(isa) => isa, 1779 None => return Ok(()), 1780 }; 1781 1782 let encoding = self.func.encodings[inst]; 1783 if encoding.is_legal() { 1784 if self.func.dfg[inst].opcode().is_ghost() { 1785 return errors.nonfatal(( 1786 inst, 1787 self.context(inst), 1788 format!( 1789 "Ghost instruction has an encoding: {}", 1790 isa.encoding_info().display(encoding), 1791 ), 1792 )); 1793 } 1794 1795 let mut encodings = isa 1796 .legal_encodings( 1797 &self.func, 1798 &self.func.dfg[inst], 1799 self.func.dfg.ctrl_typevar(inst), 1800 ) 1801 .peekable(); 1802 1803 if encodings.peek().is_none() { 1804 return errors.nonfatal(( 1805 inst, 1806 self.context(inst), 1807 format!( 1808 "Instruction failed to re-encode {}", 1809 isa.encoding_info().display(encoding), 1810 ), 1811 )); 1812 } 1813 1814 let has_valid_encoding = encodings.any(|possible_enc| encoding == possible_enc); 1815 1816 if !has_valid_encoding { 1817 let mut possible_encodings = String::new(); 1818 let mut multiple_encodings = false; 1819 1820 for enc in isa.legal_encodings( 1821 &self.func, 1822 &self.func.dfg[inst], 1823 self.func.dfg.ctrl_typevar(inst), 1824 ) { 1825 if !possible_encodings.is_empty() { 1826 possible_encodings.push_str(", "); 1827 multiple_encodings = true; 1828 } 1829 possible_encodings 1830 .write_fmt(format_args!("{}", isa.encoding_info().display(enc))) 1831 .unwrap(); 1832 } 1833 1834 return errors.nonfatal(( 1835 inst, 1836 self.context(inst), 1837 format!( 1838 "encoding {} should be {}{}", 1839 isa.encoding_info().display(encoding), 1840 if multiple_encodings { "one of: " } else { "" }, 1841 possible_encodings, 1842 ), 1843 )); 1844 } 1845 return Ok(()); 1846 } 1847 1848 // Instruction is not encoded, so it is a ghost instruction. 1849 // Instructions with side effects are not allowed to be ghost instructions. 1850 let opcode = self.func.dfg[inst].opcode(); 1851 1852 // The `fallthrough`, `fallthrough_return`, and `safepoint` instructions are not required 1853 // to have an encoding. 1854 if opcode == Opcode::Fallthrough 1855 || opcode == Opcode::FallthroughReturn 1856 || opcode == Opcode::Safepoint 1857 { 1858 return Ok(()); 1859 } 1860 1861 // Check if this opcode must be encoded. 1862 let mut needs_enc = None; 1863 if opcode.is_branch() { 1864 needs_enc = Some("Branch"); 1865 } else if opcode.is_call() { 1866 needs_enc = Some("Call"); 1867 } else if opcode.is_return() { 1868 needs_enc = Some("Return"); 1869 } else if opcode.can_store() { 1870 needs_enc = Some("Store"); 1871 } else if opcode.can_trap() { 1872 needs_enc = Some("Trapping instruction"); 1873 } else if opcode.other_side_effects() { 1874 needs_enc = Some("Instruction with side effects"); 1875 } 1876 1877 if let Some(text) = needs_enc { 1878 // This instruction needs an encoding, so generate an error. 1879 // Provide the ISA default encoding as a hint. 1880 match self.func.encode(inst, isa) { 1881 Ok(enc) => { 1882 return errors.nonfatal(( 1883 inst, 1884 self.context(inst), 1885 format!( 1886 "{} must have an encoding (e.g., {})))", 1887 text, 1888 isa.encoding_info().display(enc), 1889 ), 1890 )); 1891 } 1892 Err(_) => { 1893 return errors.nonfatal(( 1894 inst, 1895 self.context(inst), 1896 format!("{} must have an encoding", text), 1897 )) 1898 } 1899 } 1900 } 1901 1902 Ok(()) 1903 } 1904 1905 fn immediate_constraints( 1906 &self, 1907 inst: Inst, 1908 errors: &mut VerifierErrors, 1909 ) -> VerifierStepResult<()> { 1910 let inst_data = &self.func.dfg[inst]; 1911 1912 match *inst_data { 1913 ir::InstructionData::Store { flags, .. } 1914 | ir::InstructionData::StoreComplex { flags, .. } => { 1915 if flags.readonly() { 1916 errors.fatal(( 1917 inst, 1918 self.context(inst), 1919 "A store instruction cannot have the `readonly` MemFlag", 1920 )) 1921 } else { 1922 Ok(()) 1923 } 1924 } 1925 ir::InstructionData::BinaryImm8 { 1926 opcode: ir::instructions::Opcode::Extractlane, 1927 imm: lane, 1928 arg, 1929 .. 1930 } 1931 | ir::InstructionData::TernaryImm8 { 1932 opcode: ir::instructions::Opcode::Insertlane, 1933 imm: lane, 1934 args: [arg, _], 1935 .. 1936 } => { 1937 // We must be specific about the opcodes above because other instructions are using 1938 // the same formats. 1939 let ty = self.func.dfg.value_type(arg); 1940 if u16::from(lane) >= ty.lane_count() { 1941 errors.fatal(( 1942 inst, 1943 self.context(inst), 1944 format!("The lane {} does not index into the type {}", lane, ty,), 1945 )) 1946 } else { 1947 Ok(()) 1948 } 1949 } 1950 _ => Ok(()), 1951 } 1952 } 1953 1954 fn verify_safepoint_unused( 1955 &self, 1956 inst: Inst, 1957 errors: &mut VerifierErrors, 1958 ) -> VerifierStepResult<()> { 1959 if let Some(isa) = self.isa { 1960 if !isa.flags().enable_safepoints() && self.func.dfg[inst].opcode() == Opcode::Safepoint 1961 { 1962 return errors.fatal(( 1963 inst, 1964 self.context(inst), 1965 "safepoint instruction cannot be used when it is not enabled.", 1966 )); 1967 } 1968 } 1969 Ok(()) 1970 } 1971 1972 fn typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> { 1973 self.func 1974 .signature 1975 .params 1976 .iter() 1977 .enumerate() 1978 .filter(|(_, ¶m)| param.value_type == types::INVALID) 1979 .for_each(|(i, _)| { 1980 errors.report(( 1981 AnyEntity::Function, 1982 format!("Parameter at position {} has an invalid type", i), 1983 )); 1984 }); 1985 1986 self.func 1987 .signature 1988 .returns 1989 .iter() 1990 .enumerate() 1991 .filter(|(_, &ret)| ret.value_type == types::INVALID) 1992 .for_each(|(i, _)| { 1993 errors.report(( 1994 AnyEntity::Function, 1995 format!("Return value at position {} has an invalid type", i), 1996 )) 1997 }); 1998 1999 self.func 2000 .signature 2001 .returns 2002 .iter() 2003 .enumerate() 2004 .for_each(|(i, ret)| { 2005 if let ArgumentPurpose::StructArgument(_) = ret.purpose { 2006 errors.report(( 2007 AnyEntity::Function, 2008 format!("Return value at position {} can't be an struct argument", i), 2009 )) 2010 } 2011 }); 2012 2013 if errors.has_error() { 2014 Err(()) 2015 } else { 2016 Ok(()) 2017 } 2018 } 2019 2020 pub fn run(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> { 2021 self.verify_global_values(errors)?; 2022 self.verify_heaps(errors)?; 2023 self.verify_tables(errors)?; 2024 self.verify_jump_tables(errors)?; 2025 self.typecheck_entry_block_params(errors)?; 2026 self.typecheck_function_signature(errors)?; 2027 2028 for block in self.func.layout.blocks() { 2029 if self.func.layout.first_inst(block).is_none() { 2030 return errors.fatal((block, format!("{} cannot be empty", block))); 2031 } 2032 for inst in self.func.layout.block_insts(block) { 2033 self.block_integrity(block, inst, errors)?; 2034 self.instruction_integrity(inst, errors)?; 2035 self.verify_safepoint_unused(inst, errors)?; 2036 self.typecheck(inst, errors)?; 2037 self.verify_encoding(inst, errors)?; 2038 self.immediate_constraints(inst, errors)?; 2039 } 2040 2041 self.encodable_as_bb(block, errors)?; 2042 } 2043 2044 verify_flags(self.func, &self.expected_cfg, self.isa, errors)?; 2045 2046 if !errors.is_empty() { 2047 log::warn!( 2048 "Found verifier errors in function:\n{}", 2049 pretty_verifier_error(self.func, None, None, errors.clone()) 2050 ); 2051 } 2052 2053 Ok(()) 2054 } 2055 } 2056 2057 #[cfg(test)] 2058 mod tests { 2059 use super::{Verifier, VerifierError, VerifierErrors}; 2060 use crate::entity::EntityList; 2061 use crate::ir::instructions::{InstructionData, Opcode}; 2062 use crate::ir::{types, AbiParam, Function}; 2063 use crate::settings; 2064 2065 macro_rules! assert_err_with_msg { 2066 ($e:expr, $msg:expr) => { 2067 match $e.0.get(0) { 2068 None => panic!("Expected an error"), 2069 Some(&VerifierError { ref message, .. }) => { 2070 if !message.contains($msg) { 2071 #[cfg(feature = "std")] 2072 panic!("'{}' did not contain the substring '{}'", message, $msg); 2073 #[cfg(not(feature = "std"))] 2074 panic!("error message did not contain the expected substring"); 2075 } 2076 } 2077 } 2078 }; 2079 } 2080 2081 #[test] 2082 fn empty() { 2083 let func = Function::new(); 2084 let flags = &settings::Flags::new(settings::builder()); 2085 let verifier = Verifier::new(&func, flags.into()); 2086 let mut errors = VerifierErrors::default(); 2087 2088 assert_eq!(verifier.run(&mut errors), Ok(())); 2089 assert!(errors.0.is_empty()); 2090 } 2091 2092 #[test] 2093 fn bad_instruction_format() { 2094 let mut func = Function::new(); 2095 let block0 = func.dfg.make_block(); 2096 func.layout.append_block(block0); 2097 let nullary_with_bad_opcode = func.dfg.make_inst(InstructionData::UnaryImm { 2098 opcode: Opcode::F32const, 2099 imm: 0.into(), 2100 }); 2101 func.layout.append_inst(nullary_with_bad_opcode, block0); 2102 func.layout.append_inst( 2103 func.dfg.make_inst(InstructionData::Jump { 2104 opcode: Opcode::Jump, 2105 destination: block0, 2106 args: EntityList::default(), 2107 }), 2108 block0, 2109 ); 2110 let flags = &settings::Flags::new(settings::builder()); 2111 let verifier = Verifier::new(&func, flags.into()); 2112 let mut errors = VerifierErrors::default(); 2113 2114 let _ = verifier.run(&mut errors); 2115 2116 assert_err_with_msg!(errors, "instruction format"); 2117 } 2118 2119 #[test] 2120 fn test_function_invalid_param() { 2121 let mut func = Function::new(); 2122 func.signature.params.push(AbiParam::new(types::INVALID)); 2123 2124 let mut errors = VerifierErrors::default(); 2125 let flags = &settings::Flags::new(settings::builder()); 2126 let verifier = Verifier::new(&func, flags.into()); 2127 2128 let _ = verifier.typecheck_function_signature(&mut errors); 2129 assert_err_with_msg!(errors, "Parameter at position 0 has an invalid type"); 2130 } 2131 2132 #[test] 2133 fn test_function_invalid_return_value() { 2134 let mut func = Function::new(); 2135 func.signature.returns.push(AbiParam::new(types::INVALID)); 2136 2137 let mut errors = VerifierErrors::default(); 2138 let flags = &settings::Flags::new(settings::builder()); 2139 let verifier = Verifier::new(&func, flags.into()); 2140 2141 let _ = verifier.typecheck_function_signature(&mut errors); 2142 assert_err_with_msg!(errors, "Return value at position 0 has an invalid type"); 2143 } 2144 2145 #[test] 2146 fn test_printing_contextual_errors() { 2147 // Build function. 2148 let mut func = Function::new(); 2149 let block0 = func.dfg.make_block(); 2150 func.layout.append_block(block0); 2151 2152 // Build instruction: v0, v1 = iconst 42 2153 let inst = func.dfg.make_inst(InstructionData::UnaryImm { 2154 opcode: Opcode::Iconst, 2155 imm: 42.into(), 2156 }); 2157 func.dfg.append_result(inst, types::I32); 2158 func.dfg.append_result(inst, types::I32); 2159 func.layout.append_inst(inst, block0); 2160 2161 // Setup verifier. 2162 let mut errors = VerifierErrors::default(); 2163 let flags = &settings::Flags::new(settings::builder()); 2164 let verifier = Verifier::new(&func, flags.into()); 2165 2166 // Now the error message, when printed, should contain the instruction sequence causing the 2167 // error (i.e. v0, v1 = iconst.i32 42) and not only its entity value (i.e. inst0) 2168 let _ = verifier.typecheck_results(inst, types::I32, &mut errors); 2169 assert_eq!( 2170 format!("{}", errors.0[0]), 2171 "inst0 (v0, v1 = iconst.i32 42): has more result values than expected" 2172 ) 2173 } 2174 2175 #[test] 2176 fn test_empty_block() { 2177 let mut func = Function::new(); 2178 let block0 = func.dfg.make_block(); 2179 func.layout.append_block(block0); 2180 2181 let flags = &settings::Flags::new(settings::builder()); 2182 let verifier = Verifier::new(&func, flags.into()); 2183 let mut errors = VerifierErrors::default(); 2184 let _ = verifier.run(&mut errors); 2185 2186 assert_err_with_msg!(errors, "block0 cannot be empty"); 2187 } 2188 } 2189