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