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