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, Block, Constant, FuncRef, Function, GlobalValue, Inst, InstructionData,
69     JumpTable, Opcode, SigRef, StackSlot, StackSlotKind, Type, Value, ValueDef, ValueList,
70     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.
format_context(context: &Option<String>) -> String108 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 {
from(items: (L, C, M)) -> Self131     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 {
from(items: (L, M)) -> Self149     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]
new() -> Self184     pub fn new() -> Self {
185         Self(Vec::new())
186     }
187 
188     /// Return whether no errors were reported.
189     #[inline]
is_empty(&self) -> bool190     pub fn is_empty(&self) -> bool {
191         self.0.is_empty()
192     }
193 
194     /// Return whether one or more errors were reported.
195     #[inline]
has_error(&self) -> bool196     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]
as_result(&self) -> VerifierStepResult<()>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.
report(&mut self, error: impl Into<VerifierError>)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`.
fatal(&mut self, error: impl Into<VerifierError>) -> VerifierStepResult<()>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`.
nonfatal(&mut self, error: impl Into<VerifierError>) -> VerifierStepResult<()>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 {
from(v: Vec<VerifierError>) -> Self230     fn from(v: Vec<VerifierError>) -> Self {
231         Self(v)
232     }
233 }
234 
235 impl Into<Vec<VerifierError>> for VerifierErrors {
into(self) -> Vec<VerifierError>236     fn into(self) -> Vec<VerifierError> {
237         self.0
238     }
239 }
240 
241 impl Into<VerifierResult<()>> for VerifierErrors {
into(self) -> VerifierResult<()>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 {
fmt(&self, f: &mut Formatter) -> fmt::Result252     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`.
verify_function<'a, FOI: Into<FlagsOrIsa<'a>>>( func: &Function, fisa: FOI, ) -> VerifierResult<()>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`.
verify_context<'a, FOI: Into<FlagsOrIsa<'a>>>( func: &Function, cfg: &ControlFlowGraph, domtree: &DominatorTree, fisa: FOI, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>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> {
new(func: &'a Function, fisa: FlagsOrIsa<'a>) -> Self305     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]
context(&self, inst: Inst) -> String318     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.
verify_global_values(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()>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 
verify_heaps(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()>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 
verify_tables(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()>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 
verify_jump_tables(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()>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.
encodable_as_bb(&self, block: Block, errors: &mut VerifierErrors) -> VerifierStepResult<()>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 
block_integrity( &self, block: Block, inst: Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>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 
instruction_integrity( &self, inst: Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>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 
verify_entity_references( &self, inst: Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>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             Unary { .. }
753             | UnaryConst { .. }
754             | UnaryImm { .. }
755             | UnaryIeee32 { .. }
756             | UnaryIeee64 { .. }
757             | UnaryBool { .. }
758             | Binary { .. }
759             | BinaryImm { .. }
760             | Ternary { .. }
761             | InsertLane { .. }
762             | ExtractLane { .. }
763             | Shuffle { .. }
764             | IntCompare { .. }
765             | IntCompareImm { .. }
766             | IntCond { .. }
767             | FloatCompare { .. }
768             | FloatCond { .. }
769             | IntSelect { .. }
770             | Load { .. }
771             | Store { .. }
772             | RegMove { .. }
773             | CopySpecial { .. }
774             | CopyToSsa { .. }
775             | Trap { .. }
776             | CondTrap { .. }
777             | IntCondTrap { .. }
778             | FloatCondTrap { .. }
779             | NullAry { .. } => {}
780         }
781 
782         Ok(())
783     }
784 
verify_block( &self, loc: impl Into<AnyEntity>, e: Block, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>785     fn verify_block(
786         &self,
787         loc: impl Into<AnyEntity>,
788         e: Block,
789         errors: &mut VerifierErrors,
790     ) -> VerifierStepResult<()> {
791         if !self.func.dfg.block_is_valid(e) || !self.func.layout.is_block_inserted(e) {
792             return errors.fatal((loc, format!("invalid block reference {}", e)));
793         }
794         if let Some(entry_block) = self.func.layout.entry_block() {
795             if e == entry_block {
796                 return errors.fatal((loc, format!("invalid reference to entry block {}", e)));
797             }
798         }
799         Ok(())
800     }
801 
verify_sig_ref( &self, inst: Inst, s: SigRef, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>802     fn verify_sig_ref(
803         &self,
804         inst: Inst,
805         s: SigRef,
806         errors: &mut VerifierErrors,
807     ) -> VerifierStepResult<()> {
808         if !self.func.dfg.signatures.is_valid(s) {
809             errors.fatal((
810                 inst,
811                 self.context(inst),
812                 format!("invalid signature reference {}", s),
813             ))
814         } else {
815             Ok(())
816         }
817     }
818 
verify_func_ref( &self, inst: Inst, f: FuncRef, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>819     fn verify_func_ref(
820         &self,
821         inst: Inst,
822         f: FuncRef,
823         errors: &mut VerifierErrors,
824     ) -> VerifierStepResult<()> {
825         if !self.func.dfg.ext_funcs.is_valid(f) {
826             errors.nonfatal((
827                 inst,
828                 self.context(inst),
829                 format!("invalid function reference {}", f),
830             ))
831         } else {
832             Ok(())
833         }
834     }
835 
verify_stack_slot( &self, inst: Inst, ss: StackSlot, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>836     fn verify_stack_slot(
837         &self,
838         inst: Inst,
839         ss: StackSlot,
840         errors: &mut VerifierErrors,
841     ) -> VerifierStepResult<()> {
842         if !self.func.stack_slots.is_valid(ss) {
843             errors.nonfatal((
844                 inst,
845                 self.context(inst),
846                 format!("invalid stack slot {}", ss),
847             ))
848         } else {
849             Ok(())
850         }
851     }
852 
verify_global_value( &self, inst: Inst, gv: GlobalValue, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>853     fn verify_global_value(
854         &self,
855         inst: Inst,
856         gv: GlobalValue,
857         errors: &mut VerifierErrors,
858     ) -> VerifierStepResult<()> {
859         if !self.func.global_values.is_valid(gv) {
860             errors.nonfatal((
861                 inst,
862                 self.context(inst),
863                 format!("invalid global value {}", gv),
864             ))
865         } else {
866             Ok(())
867         }
868     }
869 
verify_heap( &self, inst: Inst, heap: ir::Heap, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>870     fn verify_heap(
871         &self,
872         inst: Inst,
873         heap: ir::Heap,
874         errors: &mut VerifierErrors,
875     ) -> VerifierStepResult<()> {
876         if !self.func.heaps.is_valid(heap) {
877             errors.nonfatal((inst, self.context(inst), format!("invalid heap {}", heap)))
878         } else {
879             Ok(())
880         }
881     }
882 
verify_table( &self, inst: Inst, table: ir::Table, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>883     fn verify_table(
884         &self,
885         inst: Inst,
886         table: ir::Table,
887         errors: &mut VerifierErrors,
888     ) -> VerifierStepResult<()> {
889         if !self.func.tables.is_valid(table) {
890             errors.nonfatal((inst, self.context(inst), format!("invalid table {}", table)))
891         } else {
892             Ok(())
893         }
894     }
895 
verify_value_list( &self, inst: Inst, l: &ValueList, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>896     fn verify_value_list(
897         &self,
898         inst: Inst,
899         l: &ValueList,
900         errors: &mut VerifierErrors,
901     ) -> VerifierStepResult<()> {
902         if !l.is_valid(&self.func.dfg.value_lists) {
903             errors.nonfatal((
904                 inst,
905                 self.context(inst),
906                 format!("invalid value list reference {:?}", l),
907             ))
908         } else {
909             Ok(())
910         }
911     }
912 
verify_jump_table( &self, inst: Inst, j: JumpTable, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>913     fn verify_jump_table(
914         &self,
915         inst: Inst,
916         j: JumpTable,
917         errors: &mut VerifierErrors,
918     ) -> VerifierStepResult<()> {
919         if !self.func.jump_tables.is_valid(j) {
920             errors.nonfatal((
921                 inst,
922                 self.context(inst),
923                 format!("invalid jump table reference {}", j),
924             ))
925         } else {
926             Ok(())
927         }
928     }
929 
verify_value( &self, loc_inst: Inst, v: Value, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>930     fn verify_value(
931         &self,
932         loc_inst: Inst,
933         v: Value,
934         errors: &mut VerifierErrors,
935     ) -> VerifierStepResult<()> {
936         let dfg = &self.func.dfg;
937         if !dfg.value_is_valid(v) {
938             errors.nonfatal((
939                 loc_inst,
940                 self.context(loc_inst),
941                 format!("invalid value reference {}", v),
942             ))
943         } else {
944             Ok(())
945         }
946     }
947 
verify_inst_arg( &self, loc_inst: Inst, v: Value, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>948     fn verify_inst_arg(
949         &self,
950         loc_inst: Inst,
951         v: Value,
952         errors: &mut VerifierErrors,
953     ) -> VerifierStepResult<()> {
954         self.verify_value(loc_inst, v, errors)?;
955 
956         let dfg = &self.func.dfg;
957         let loc_block = self.func.layout.pp_block(loc_inst);
958         let is_reachable = self.expected_domtree.is_reachable(loc_block);
959 
960         // SSA form
961         match dfg.value_def(v) {
962             ValueDef::Result(def_inst, _) => {
963                 // Value is defined by an instruction that exists.
964                 if !dfg.inst_is_valid(def_inst) {
965                     return errors.fatal((
966                         loc_inst,
967                         self.context(loc_inst),
968                         format!("{} is defined by invalid instruction {}", v, def_inst),
969                     ));
970                 }
971                 // Defining instruction is inserted in a block.
972                 if self.func.layout.inst_block(def_inst) == None {
973                     return errors.fatal((
974                         loc_inst,
975                         self.context(loc_inst),
976                         format!("{} is defined by {} which has no block", v, def_inst),
977                     ));
978                 }
979                 // Defining instruction dominates the instruction that uses the value.
980                 if is_reachable {
981                     if !self
982                         .expected_domtree
983                         .dominates(def_inst, loc_inst, &self.func.layout)
984                     {
985                         return errors.fatal((
986                             loc_inst,
987                             self.context(loc_inst),
988                             format!("uses value {} from non-dominating {}", v, def_inst),
989                         ));
990                     }
991                     if def_inst == loc_inst {
992                         return errors.fatal((
993                             loc_inst,
994                             self.context(loc_inst),
995                             format!("uses value {} from itself", v),
996                         ));
997                     }
998                 }
999             }
1000             ValueDef::Param(block, _) => {
1001                 // Value is defined by an existing block.
1002                 if !dfg.block_is_valid(block) {
1003                     return errors.fatal((
1004                         loc_inst,
1005                         self.context(loc_inst),
1006                         format!("{} is defined by invalid block {}", v, block),
1007                     ));
1008                 }
1009                 // Defining block is inserted in the layout
1010                 if !self.func.layout.is_block_inserted(block) {
1011                     return errors.fatal((
1012                         loc_inst,
1013                         self.context(loc_inst),
1014                         format!("{} is defined by {} which is not in the layout", v, block),
1015                     ));
1016                 }
1017                 // The defining block dominates the instruction using this value.
1018                 if is_reachable
1019                     && !self
1020                         .expected_domtree
1021                         .dominates(block, loc_inst, &self.func.layout)
1022                 {
1023                     return errors.fatal((
1024                         loc_inst,
1025                         self.context(loc_inst),
1026                         format!("uses value arg from non-dominating {}", block),
1027                     ));
1028                 }
1029             }
1030         }
1031         Ok(())
1032     }
1033 
verify_inst_result( &self, loc_inst: Inst, v: Value, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1034     fn verify_inst_result(
1035         &self,
1036         loc_inst: Inst,
1037         v: Value,
1038         errors: &mut VerifierErrors,
1039     ) -> VerifierStepResult<()> {
1040         self.verify_value(loc_inst, v, errors)?;
1041 
1042         match self.func.dfg.value_def(v) {
1043             ValueDef::Result(def_inst, _) => {
1044                 if def_inst != loc_inst {
1045                     errors.fatal((
1046                         loc_inst,
1047                         self.context(loc_inst),
1048                         format!("instruction result {} is not defined by the instruction", v),
1049                     ))
1050                 } else {
1051                     Ok(())
1052                 }
1053             }
1054             ValueDef::Param(_, _) => errors.fatal((
1055                 loc_inst,
1056                 self.context(loc_inst),
1057                 format!("instruction result {} is not defined by the instruction", v),
1058             )),
1059         }
1060     }
1061 
verify_bitcast( &self, inst: Inst, arg: Value, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1062     fn verify_bitcast(
1063         &self,
1064         inst: Inst,
1065         arg: Value,
1066         errors: &mut VerifierErrors,
1067     ) -> VerifierStepResult<()> {
1068         let typ = self.func.dfg.ctrl_typevar(inst);
1069         let value_type = self.func.dfg.value_type(arg);
1070 
1071         if typ.lane_bits() < value_type.lane_bits() {
1072             errors.fatal((
1073                 inst,
1074                 format!(
1075                     "The bitcast argument {} doesn't fit in a type of {} bits",
1076                     arg,
1077                     typ.lane_bits()
1078                 ),
1079             ))
1080         } else {
1081             Ok(())
1082         }
1083     }
1084 
verify_constant_size( &self, inst: Inst, constant: Constant, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1085     fn verify_constant_size(
1086         &self,
1087         inst: Inst,
1088         constant: Constant,
1089         errors: &mut VerifierErrors,
1090     ) -> VerifierStepResult<()> {
1091         let type_size = self.func.dfg.ctrl_typevar(inst).bytes() as usize;
1092         let constant_size = self.func.dfg.constants.get(constant).len();
1093         if type_size != constant_size {
1094             errors.fatal((
1095                 inst,
1096                 format!(
1097                     "The instruction expects {} to have a size of {} bytes but it has {}",
1098                     constant, type_size, constant_size
1099                 ),
1100             ))
1101         } else {
1102             Ok(())
1103         }
1104     }
1105 
domtree_integrity( &self, domtree: &DominatorTree, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1106     fn domtree_integrity(
1107         &self,
1108         domtree: &DominatorTree,
1109         errors: &mut VerifierErrors,
1110     ) -> VerifierStepResult<()> {
1111         // We consider two `DominatorTree`s to be equal if they return the same immediate
1112         // dominator for each block. Therefore the current domtree is valid if it matches the freshly
1113         // computed one.
1114         for block in self.func.layout.blocks() {
1115             let expected = self.expected_domtree.idom(block);
1116             let got = domtree.idom(block);
1117             if got != expected {
1118                 return errors.fatal((
1119                     block,
1120                     format!(
1121                         "invalid domtree, expected idom({}) = {:?}, got {:?}",
1122                         block, expected, got
1123                     ),
1124                 ));
1125             }
1126         }
1127         // We also verify if the postorder defined by `DominatorTree` is sane
1128         if domtree.cfg_postorder().len() != self.expected_domtree.cfg_postorder().len() {
1129             return errors.fatal((
1130                 AnyEntity::Function,
1131                 "incorrect number of Blocks in postorder traversal",
1132             ));
1133         }
1134         for (index, (&test_block, &true_block)) in domtree
1135             .cfg_postorder()
1136             .iter()
1137             .zip(self.expected_domtree.cfg_postorder().iter())
1138             .enumerate()
1139         {
1140             if test_block != true_block {
1141                 return errors.fatal((
1142                     test_block,
1143                     format!(
1144                         "invalid domtree, postorder block number {} should be {}, got {}",
1145                         index, true_block, test_block
1146                     ),
1147                 ));
1148             }
1149         }
1150         // We verify rpo_cmp on pairs of adjacent blocks in the postorder
1151         for (&prev_block, &next_block) in domtree.cfg_postorder().iter().adjacent_pairs() {
1152             if self
1153                 .expected_domtree
1154                 .rpo_cmp(prev_block, next_block, &self.func.layout)
1155                 != Ordering::Greater
1156             {
1157                 return errors.fatal((
1158                     next_block,
1159                     format!(
1160                         "invalid domtree, rpo_cmp does not says {} is greater than {}",
1161                         prev_block, next_block
1162                     ),
1163                 ));
1164             }
1165         }
1166         Ok(())
1167     }
1168 
typecheck_entry_block_params(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()>1169     fn typecheck_entry_block_params(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
1170         if let Some(block) = self.func.layout.entry_block() {
1171             let expected_types = &self.func.signature.params;
1172             let block_param_count = self.func.dfg.num_block_params(block);
1173 
1174             if block_param_count != expected_types.len() {
1175                 return errors.fatal((
1176                     block,
1177                     format!(
1178                         "entry block parameters ({}) must match function signature ({})",
1179                         block_param_count,
1180                         expected_types.len()
1181                     ),
1182                 ));
1183             }
1184 
1185             for (i, &arg) in self.func.dfg.block_params(block).iter().enumerate() {
1186                 let arg_type = self.func.dfg.value_type(arg);
1187                 if arg_type != expected_types[i].value_type {
1188                     errors.report((
1189                         block,
1190                         format!(
1191                             "entry block parameter {} expected to have type {}, got {}",
1192                             i, expected_types[i], arg_type
1193                         ),
1194                     ));
1195                 }
1196             }
1197         }
1198 
1199         errors.as_result()
1200     }
1201 
typecheck(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()>1202     fn typecheck(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
1203         let inst_data = &self.func.dfg[inst];
1204         let constraints = inst_data.opcode().constraints();
1205 
1206         let ctrl_type = if let Some(value_typeset) = constraints.ctrl_typeset() {
1207             // For polymorphic opcodes, determine the controlling type variable first.
1208             let ctrl_type = self.func.dfg.ctrl_typevar(inst);
1209 
1210             if !value_typeset.contains(ctrl_type) {
1211                 errors.report((
1212                     inst,
1213                     self.context(inst),
1214                     format!("has an invalid controlling type {}", ctrl_type),
1215                 ));
1216             }
1217 
1218             ctrl_type
1219         } else {
1220             // Non-polymorphic instructions don't check the controlling type variable, so `Option`
1221             // is unnecessary and we can just make it `INVALID`.
1222             types::INVALID
1223         };
1224 
1225         // Typechecking instructions is never fatal
1226         let _ = self.typecheck_results(inst, ctrl_type, errors);
1227         let _ = self.typecheck_fixed_args(inst, ctrl_type, errors);
1228         let _ = self.typecheck_variable_args(inst, errors);
1229         let _ = self.typecheck_return(inst, errors);
1230         let _ = self.typecheck_special(inst, ctrl_type, errors);
1231 
1232         // Misuses of copy_nop instructions are fatal
1233         self.typecheck_copy_nop(inst, errors)?;
1234 
1235         Ok(())
1236     }
1237 
typecheck_results( &self, inst: Inst, ctrl_type: Type, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1238     fn typecheck_results(
1239         &self,
1240         inst: Inst,
1241         ctrl_type: Type,
1242         errors: &mut VerifierErrors,
1243     ) -> VerifierStepResult<()> {
1244         let mut i = 0;
1245         for &result in self.func.dfg.inst_results(inst) {
1246             let result_type = self.func.dfg.value_type(result);
1247             let expected_type = self.func.dfg.compute_result_type(inst, i, ctrl_type);
1248             if let Some(expected_type) = expected_type {
1249                 if result_type != expected_type {
1250                     errors.report((
1251                         inst,
1252                         self.context(inst),
1253                         format!(
1254                             "expected result {} ({}) to have type {}, found {}",
1255                             i, result, expected_type, result_type
1256                         ),
1257                     ));
1258                 }
1259             } else {
1260                 return errors.nonfatal((
1261                     inst,
1262                     self.context(inst),
1263                     "has more result values than expected",
1264                 ));
1265             }
1266             i += 1;
1267         }
1268 
1269         // There aren't any more result types left.
1270         if self.func.dfg.compute_result_type(inst, i, ctrl_type) != None {
1271             return errors.nonfatal((
1272                 inst,
1273                 self.context(inst),
1274                 "has fewer result values than expected",
1275             ));
1276         }
1277         Ok(())
1278     }
1279 
typecheck_fixed_args( &self, inst: Inst, ctrl_type: Type, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1280     fn typecheck_fixed_args(
1281         &self,
1282         inst: Inst,
1283         ctrl_type: Type,
1284         errors: &mut VerifierErrors,
1285     ) -> VerifierStepResult<()> {
1286         let constraints = self.func.dfg[inst].opcode().constraints();
1287 
1288         for (i, &arg) in self.func.dfg.inst_fixed_args(inst).iter().enumerate() {
1289             let arg_type = self.func.dfg.value_type(arg);
1290             match constraints.value_argument_constraint(i, ctrl_type) {
1291                 ResolvedConstraint::Bound(expected_type) => {
1292                     if arg_type != expected_type {
1293                         errors.report((
1294                             inst,
1295                             self.context(inst),
1296                             format!(
1297                                 "arg {} ({}) has type {}, expected {}",
1298                                 i, arg, arg_type, expected_type
1299                             ),
1300                         ));
1301                     }
1302                 }
1303                 ResolvedConstraint::Free(type_set) => {
1304                     if !type_set.contains(arg_type) {
1305                         errors.report((
1306                             inst,
1307                             self.context(inst),
1308                             format!(
1309                                 "arg {} ({}) with type {} failed to satisfy type set {:?}",
1310                                 i, arg, arg_type, type_set
1311                             ),
1312                         ));
1313                     }
1314                 }
1315             }
1316         }
1317         Ok(())
1318     }
1319 
typecheck_variable_args( &self, inst: Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1320     fn typecheck_variable_args(
1321         &self,
1322         inst: Inst,
1323         errors: &mut VerifierErrors,
1324     ) -> VerifierStepResult<()> {
1325         match self.func.dfg.analyze_branch(inst) {
1326             BranchInfo::SingleDest(block, _) => {
1327                 let iter = self
1328                     .func
1329                     .dfg
1330                     .block_params(block)
1331                     .iter()
1332                     .map(|&v| self.func.dfg.value_type(v));
1333                 self.typecheck_variable_args_iterator(inst, iter, errors)?;
1334             }
1335             BranchInfo::Table(table, block) => {
1336                 if let Some(block) = block {
1337                     let arg_count = self.func.dfg.num_block_params(block);
1338                     if arg_count != 0 {
1339                         return errors.nonfatal((
1340                             inst,
1341                             self.context(inst),
1342                             format!(
1343                                 "takes no arguments, but had target {} with {} arguments",
1344                                 block, arg_count,
1345                             ),
1346                         ));
1347                     }
1348                 }
1349                 for block in self.func.jump_tables[table].iter() {
1350                     let arg_count = self.func.dfg.num_block_params(*block);
1351                     if arg_count != 0 {
1352                         return errors.nonfatal((
1353                             inst,
1354                             self.context(inst),
1355                             format!(
1356                                 "takes no arguments, but had target {} with {} arguments",
1357                                 block, arg_count,
1358                             ),
1359                         ));
1360                     }
1361                 }
1362             }
1363             BranchInfo::NotABranch => {}
1364         }
1365 
1366         match self.func.dfg[inst].analyze_call(&self.func.dfg.value_lists) {
1367             CallInfo::Direct(func_ref, _) => {
1368                 let sig_ref = self.func.dfg.ext_funcs[func_ref].signature;
1369                 let arg_types = self.func.dfg.signatures[sig_ref]
1370                     .params
1371                     .iter()
1372                     .map(|a| a.value_type);
1373                 self.typecheck_variable_args_iterator(inst, arg_types, errors)?;
1374                 self.check_outgoing_args(inst, sig_ref, errors)?;
1375             }
1376             CallInfo::Indirect(sig_ref, _) => {
1377                 let arg_types = self.func.dfg.signatures[sig_ref]
1378                     .params
1379                     .iter()
1380                     .map(|a| a.value_type);
1381                 self.typecheck_variable_args_iterator(inst, arg_types, errors)?;
1382                 self.check_outgoing_args(inst, sig_ref, errors)?;
1383             }
1384             CallInfo::NotACall => {}
1385         }
1386         Ok(())
1387     }
1388 
typecheck_variable_args_iterator<I: Iterator<Item = Type>>( &self, inst: Inst, iter: I, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1389     fn typecheck_variable_args_iterator<I: Iterator<Item = Type>>(
1390         &self,
1391         inst: Inst,
1392         iter: I,
1393         errors: &mut VerifierErrors,
1394     ) -> VerifierStepResult<()> {
1395         let variable_args = self.func.dfg.inst_variable_args(inst);
1396         let mut i = 0;
1397 
1398         for expected_type in iter {
1399             if i >= variable_args.len() {
1400                 // Result count mismatch handled below, we want the full argument count first though
1401                 i += 1;
1402                 continue;
1403             }
1404             let arg = variable_args[i];
1405             let arg_type = self.func.dfg.value_type(arg);
1406             if expected_type != arg_type {
1407                 errors.report((
1408                     inst,
1409                     self.context(inst),
1410                     format!(
1411                         "arg {} ({}) has type {}, expected {}",
1412                         i, variable_args[i], arg_type, expected_type
1413                     ),
1414                 ));
1415             }
1416             i += 1;
1417         }
1418         if i != variable_args.len() {
1419             return errors.nonfatal((
1420                 inst,
1421                 self.context(inst),
1422                 format!(
1423                     "mismatched argument count for `{}`: got {}, expected {}",
1424                     self.func.dfg.display_inst(inst, None),
1425                     variable_args.len(),
1426                     i,
1427                 ),
1428             ));
1429         }
1430         Ok(())
1431     }
1432 
1433     /// Check the locations assigned to outgoing call arguments.
1434     ///
1435     /// When a signature has been legalized, all values passed as outgoing arguments on the stack
1436     /// must be assigned to a matching `OutgoingArg` stack slot.
check_outgoing_args( &self, inst: Inst, sig_ref: SigRef, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1437     fn check_outgoing_args(
1438         &self,
1439         inst: Inst,
1440         sig_ref: SigRef,
1441         errors: &mut VerifierErrors,
1442     ) -> VerifierStepResult<()> {
1443         let sig = &self.func.dfg.signatures[sig_ref];
1444 
1445         let args = self.func.dfg.inst_variable_args(inst);
1446         let expected_args = &sig.params[..];
1447 
1448         for (&arg, &abi) in args.iter().zip(expected_args) {
1449             // Value types have already been checked by `typecheck_variable_args_iterator()`.
1450             if let ArgumentLoc::Stack(offset) = abi.location {
1451                 let arg_loc = self.func.locations[arg];
1452                 if let ValueLoc::Stack(ss) = arg_loc {
1453                     // Argument value is assigned to a stack slot as expected.
1454                     self.verify_stack_slot(inst, ss, errors)?;
1455                     let slot = &self.func.stack_slots[ss];
1456                     if slot.kind != StackSlotKind::OutgoingArg {
1457                         return errors.fatal((
1458                             inst,
1459                             self.context(inst),
1460                             format!(
1461                                 "Outgoing stack argument {} in wrong stack slot: {} = {}",
1462                                 arg, ss, slot,
1463                             ),
1464                         ));
1465                     }
1466                     if slot.offset != Some(offset) {
1467                         return errors.fatal((
1468                             inst,
1469                             self.context(inst),
1470                             format!(
1471                                 "Outgoing stack argument {} should have offset {}: {} = {}",
1472                                 arg, offset, ss, slot,
1473                             ),
1474                         ));
1475                     }
1476                     if slot.size != abi.value_type.bytes() {
1477                         return errors.fatal((
1478                             inst,
1479                             self.context(inst),
1480                             format!(
1481                                 "Outgoing stack argument {} wrong size for {}: {} = {}",
1482                                 arg, abi.value_type, ss, slot,
1483                             ),
1484                         ));
1485                     }
1486                 } else {
1487                     let reginfo = self.isa.map(|i| i.register_info());
1488                     return errors.fatal((
1489                         inst,
1490                         self.context(inst),
1491                         format!(
1492                             "Outgoing stack argument {} in wrong location: {}",
1493                             arg,
1494                             arg_loc.display(reginfo.as_ref())
1495                         ),
1496                     ));
1497                 }
1498             }
1499         }
1500         Ok(())
1501     }
1502 
typecheck_return(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()>1503     fn typecheck_return(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
1504         if self.func.dfg[inst].opcode().is_return() {
1505             let args = self.func.dfg.inst_variable_args(inst);
1506             let expected_types = &self.func.signature.returns;
1507             if args.len() != expected_types.len() {
1508                 return errors.nonfatal((
1509                     inst,
1510                     self.context(inst),
1511                     "arguments of return must match function signature",
1512                 ));
1513             }
1514             for (i, (&arg, &expected_type)) in args.iter().zip(expected_types).enumerate() {
1515                 let arg_type = self.func.dfg.value_type(arg);
1516                 if arg_type != expected_type.value_type {
1517                     errors.report((
1518                         inst,
1519                         self.context(inst),
1520                         format!(
1521                             "arg {} ({}) has type {}, must match function signature of {}",
1522                             i, arg, arg_type, expected_type
1523                         ),
1524                     ));
1525                 }
1526             }
1527         }
1528         Ok(())
1529     }
1530 
1531     // Check special-purpose type constraints that can't be expressed in the normal opcode
1532     // constraints.
typecheck_special( &self, inst: Inst, ctrl_type: Type, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1533     fn typecheck_special(
1534         &self,
1535         inst: Inst,
1536         ctrl_type: Type,
1537         errors: &mut VerifierErrors,
1538     ) -> VerifierStepResult<()> {
1539         match self.func.dfg[inst] {
1540             ir::InstructionData::Unary { opcode, arg } => {
1541                 let arg_type = self.func.dfg.value_type(arg);
1542                 match opcode {
1543                     Opcode::Bextend | Opcode::Uextend | Opcode::Sextend | Opcode::Fpromote => {
1544                         if arg_type.lane_count() != ctrl_type.lane_count() {
1545                             return errors.nonfatal((
1546                                 inst,
1547                                 self.context(inst),
1548                                 format!(
1549                                     "input {} and output {} must have same number of lanes",
1550                                     arg_type, ctrl_type,
1551                                 ),
1552                             ));
1553                         }
1554                         if arg_type.lane_bits() >= ctrl_type.lane_bits() {
1555                             return errors.nonfatal((
1556                                 inst,
1557                                 self.context(inst),
1558                                 format!(
1559                                     "input {} must be smaller than output {}",
1560                                     arg_type, ctrl_type,
1561                                 ),
1562                             ));
1563                         }
1564                     }
1565                     Opcode::Breduce | Opcode::Ireduce | Opcode::Fdemote => {
1566                         if arg_type.lane_count() != ctrl_type.lane_count() {
1567                             return errors.nonfatal((
1568                                 inst,
1569                                 self.context(inst),
1570                                 format!(
1571                                     "input {} and output {} must have same number of lanes",
1572                                     arg_type, ctrl_type,
1573                                 ),
1574                             ));
1575                         }
1576                         if arg_type.lane_bits() <= ctrl_type.lane_bits() {
1577                             return errors.nonfatal((
1578                                 inst,
1579                                 self.context(inst),
1580                                 format!(
1581                                     "input {} must be larger than output {}",
1582                                     arg_type, ctrl_type,
1583                                 ),
1584                             ));
1585                         }
1586                     }
1587                     _ => {}
1588                 }
1589             }
1590             ir::InstructionData::HeapAddr { heap, arg, .. } => {
1591                 let index_type = self.func.dfg.value_type(arg);
1592                 let heap_index_type = self.func.heaps[heap].index_type;
1593                 if index_type != heap_index_type {
1594                     return errors.nonfatal((
1595                         inst,
1596                         self.context(inst),
1597                         format!(
1598                             "index type {} differs from heap index type {}",
1599                             index_type, heap_index_type,
1600                         ),
1601                     ));
1602                 }
1603             }
1604             ir::InstructionData::TableAddr { table, arg, .. } => {
1605                 let index_type = self.func.dfg.value_type(arg);
1606                 let table_index_type = self.func.tables[table].index_type;
1607                 if index_type != table_index_type {
1608                     return errors.nonfatal((
1609                         inst,
1610                         self.context(inst),
1611                         format!(
1612                             "index type {} differs from table index type {}",
1613                             index_type, table_index_type,
1614                         ),
1615                     ));
1616                 }
1617             }
1618             ir::InstructionData::UnaryGlobalValue { global_value, .. } => {
1619                 if let Some(isa) = self.isa {
1620                     let inst_type = self.func.dfg.value_type(self.func.dfg.first_result(inst));
1621                     let global_type = self.func.global_values[global_value].global_type(isa);
1622                     if inst_type != global_type {
1623                         return errors.nonfatal((
1624                             inst, self.context(inst),
1625                             format!(
1626                                 "global_value instruction with type {} references global value with type {}",
1627                                 inst_type, global_type
1628                             )),
1629                         );
1630                     }
1631                 }
1632             }
1633             _ => {}
1634         }
1635         Ok(())
1636     }
1637 
typecheck_copy_nop( &self, inst: Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1638     fn typecheck_copy_nop(
1639         &self,
1640         inst: Inst,
1641         errors: &mut VerifierErrors,
1642     ) -> VerifierStepResult<()> {
1643         if let InstructionData::Unary {
1644             opcode: Opcode::CopyNop,
1645             arg,
1646         } = self.func.dfg[inst]
1647         {
1648             let dst_vals = self.func.dfg.inst_results(inst);
1649             if dst_vals.len() != 1 {
1650                 return errors.fatal((
1651                     inst,
1652                     self.context(inst),
1653                     "copy_nop must produce exactly one result",
1654                 ));
1655             }
1656             let dst_val = dst_vals[0];
1657             if self.func.dfg.value_type(dst_val) != self.func.dfg.value_type(arg) {
1658                 return errors.fatal((
1659                     inst,
1660                     self.context(inst),
1661                     "copy_nop src and dst types must be the same",
1662                 ));
1663             }
1664             let src_loc = self.func.locations[arg];
1665             let dst_loc = self.func.locations[dst_val];
1666             let locs_ok = match (src_loc, dst_loc) {
1667                 (ValueLoc::Stack(src_slot), ValueLoc::Stack(dst_slot)) => src_slot == dst_slot,
1668                 _ => false,
1669             };
1670             if !locs_ok {
1671                 return errors.fatal((
1672                     inst,
1673                     self.context(inst),
1674                     format!(
1675                         "copy_nop must refer to identical stack slots, but found {:?} vs {:?}",
1676                         src_loc, dst_loc,
1677                     ),
1678                 ));
1679             }
1680         }
1681         Ok(())
1682     }
1683 
cfg_integrity( &self, cfg: &ControlFlowGraph, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1684     fn cfg_integrity(
1685         &self,
1686         cfg: &ControlFlowGraph,
1687         errors: &mut VerifierErrors,
1688     ) -> VerifierStepResult<()> {
1689         let mut expected_succs = BTreeSet::<Block>::new();
1690         let mut got_succs = BTreeSet::<Block>::new();
1691         let mut expected_preds = BTreeSet::<Inst>::new();
1692         let mut got_preds = BTreeSet::<Inst>::new();
1693 
1694         for block in self.func.layout.blocks() {
1695             expected_succs.extend(self.expected_cfg.succ_iter(block));
1696             got_succs.extend(cfg.succ_iter(block));
1697 
1698             let missing_succs: Vec<Block> =
1699                 expected_succs.difference(&got_succs).cloned().collect();
1700             if !missing_succs.is_empty() {
1701                 errors.report((
1702                     block,
1703                     format!("cfg lacked the following successor(s) {:?}", missing_succs),
1704                 ));
1705                 continue;
1706             }
1707 
1708             let excess_succs: Vec<Block> = got_succs.difference(&expected_succs).cloned().collect();
1709             if !excess_succs.is_empty() {
1710                 errors.report((
1711                     block,
1712                     format!("cfg had unexpected successor(s) {:?}", excess_succs),
1713                 ));
1714                 continue;
1715             }
1716 
1717             expected_preds.extend(
1718                 self.expected_cfg
1719                     .pred_iter(block)
1720                     .map(|BlockPredecessor { inst, .. }| inst),
1721             );
1722             got_preds.extend(
1723                 cfg.pred_iter(block)
1724                     .map(|BlockPredecessor { inst, .. }| inst),
1725             );
1726 
1727             let missing_preds: Vec<Inst> = expected_preds.difference(&got_preds).cloned().collect();
1728             if !missing_preds.is_empty() {
1729                 errors.report((
1730                     block,
1731                     format!(
1732                         "cfg lacked the following predecessor(s) {:?}",
1733                         missing_preds
1734                     ),
1735                 ));
1736                 continue;
1737             }
1738 
1739             let excess_preds: Vec<Inst> = got_preds.difference(&expected_preds).cloned().collect();
1740             if !excess_preds.is_empty() {
1741                 errors.report((
1742                     block,
1743                     format!("cfg had unexpected predecessor(s) {:?}", excess_preds),
1744                 ));
1745                 continue;
1746             }
1747 
1748             expected_succs.clear();
1749             got_succs.clear();
1750             expected_preds.clear();
1751             got_preds.clear();
1752         }
1753         errors.as_result()
1754     }
1755 
1756     /// If the verifier has been set up with an ISA, make sure that the recorded encoding for the
1757     /// instruction (if any) matches how the ISA would encode it.
verify_encoding(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()>1758     fn verify_encoding(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
1759         // When the encodings table is empty, we don't require any instructions to be encoded.
1760         //
1761         // Once some instructions are encoded, we require all side-effecting instructions to have a
1762         // legal encoding.
1763         if self.func.encodings.is_empty() {
1764             return Ok(());
1765         }
1766 
1767         let isa = match self.isa {
1768             Some(isa) => isa,
1769             None => return Ok(()),
1770         };
1771 
1772         let encoding = self.func.encodings[inst];
1773         if encoding.is_legal() {
1774             if self.func.dfg[inst].opcode().is_ghost() {
1775                 return errors.nonfatal((
1776                     inst,
1777                     self.context(inst),
1778                     format!(
1779                         "Ghost instruction has an encoding: {}",
1780                         isa.encoding_info().display(encoding),
1781                     ),
1782                 ));
1783             }
1784 
1785             let mut encodings = isa
1786                 .legal_encodings(
1787                     &self.func,
1788                     &self.func.dfg[inst],
1789                     self.func.dfg.ctrl_typevar(inst),
1790                 )
1791                 .peekable();
1792 
1793             if encodings.peek().is_none() {
1794                 return errors.nonfatal((
1795                     inst,
1796                     self.context(inst),
1797                     format!(
1798                         "Instruction failed to re-encode {}",
1799                         isa.encoding_info().display(encoding),
1800                     ),
1801                 ));
1802             }
1803 
1804             let has_valid_encoding = encodings.any(|possible_enc| encoding == possible_enc);
1805 
1806             if !has_valid_encoding {
1807                 let mut possible_encodings = String::new();
1808                 let mut multiple_encodings = false;
1809 
1810                 for enc in isa.legal_encodings(
1811                     &self.func,
1812                     &self.func.dfg[inst],
1813                     self.func.dfg.ctrl_typevar(inst),
1814                 ) {
1815                     if !possible_encodings.is_empty() {
1816                         possible_encodings.push_str(", ");
1817                         multiple_encodings = true;
1818                     }
1819                     possible_encodings
1820                         .write_fmt(format_args!("{}", isa.encoding_info().display(enc)))
1821                         .unwrap();
1822                 }
1823 
1824                 return errors.nonfatal((
1825                     inst,
1826                     self.context(inst),
1827                     format!(
1828                         "encoding {} should be {}{}",
1829                         isa.encoding_info().display(encoding),
1830                         if multiple_encodings { "one of: " } else { "" },
1831                         possible_encodings,
1832                     ),
1833                 ));
1834             }
1835             return Ok(());
1836         }
1837 
1838         // Instruction is not encoded, so it is a ghost instruction.
1839         // Instructions with side effects are not allowed to be ghost instructions.
1840         let opcode = self.func.dfg[inst].opcode();
1841 
1842         // The `fallthrough`, `fallthrough_return`, and `safepoint` instructions are not required
1843         // to have an encoding.
1844         if opcode == Opcode::Fallthrough
1845             || opcode == Opcode::FallthroughReturn
1846             || opcode == Opcode::Safepoint
1847         {
1848             return Ok(());
1849         }
1850 
1851         // Check if this opcode must be encoded.
1852         let mut needs_enc = None;
1853         if opcode.is_branch() {
1854             needs_enc = Some("Branch");
1855         } else if opcode.is_call() {
1856             needs_enc = Some("Call");
1857         } else if opcode.is_return() {
1858             needs_enc = Some("Return");
1859         } else if opcode.can_store() {
1860             needs_enc = Some("Store");
1861         } else if opcode.can_trap() {
1862             needs_enc = Some("Trapping instruction");
1863         } else if opcode.other_side_effects() {
1864             needs_enc = Some("Instruction with side effects");
1865         }
1866 
1867         if let Some(text) = needs_enc {
1868             // This instruction needs an encoding, so generate an error.
1869             // Provide the ISA default encoding as a hint.
1870             match self.func.encode(inst, isa) {
1871                 Ok(enc) => {
1872                     return errors.nonfatal((
1873                         inst,
1874                         self.context(inst),
1875                         format!(
1876                             "{} must have an encoding (e.g., {})))",
1877                             text,
1878                             isa.encoding_info().display(enc),
1879                         ),
1880                     ));
1881                 }
1882                 Err(_) => {
1883                     return errors.nonfatal((
1884                         inst,
1885                         self.context(inst),
1886                         format!("{} must have an encoding", text),
1887                     ))
1888                 }
1889             }
1890         }
1891 
1892         Ok(())
1893     }
1894 
immediate_constraints( &self, inst: Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1895     fn immediate_constraints(
1896         &self,
1897         inst: Inst,
1898         errors: &mut VerifierErrors,
1899     ) -> VerifierStepResult<()> {
1900         let inst_data = &self.func.dfg[inst];
1901 
1902         match *inst_data {
1903             ir::InstructionData::Store { flags, .. }
1904             | ir::InstructionData::StoreComplex { flags, .. } => {
1905                 if flags.readonly() {
1906                     errors.fatal((
1907                         inst,
1908                         self.context(inst),
1909                         "A store instruction cannot have the `readonly` MemFlag",
1910                     ))
1911                 } else {
1912                     Ok(())
1913                 }
1914             }
1915             ir::InstructionData::ExtractLane {
1916                 opcode: ir::instructions::Opcode::Extractlane,
1917                 lane,
1918                 arg,
1919                 ..
1920             }
1921             | ir::InstructionData::InsertLane {
1922                 opcode: ir::instructions::Opcode::Insertlane,
1923                 lane,
1924                 args: [arg, _],
1925                 ..
1926             } => {
1927                 // We must be specific about the opcodes above because other instructions are using
1928                 // the ExtractLane/InsertLane formats.
1929                 let ty = self.func.dfg.value_type(arg);
1930                 if u16::from(lane) >= ty.lane_count() {
1931                     errors.fatal((
1932                         inst,
1933                         self.context(inst),
1934                         format!("The lane {} does not index into the type {}", lane, ty,),
1935                     ))
1936                 } else {
1937                     Ok(())
1938                 }
1939             }
1940             _ => Ok(()),
1941         }
1942     }
1943 
verify_safepoint_unused( &self, inst: Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>1944     fn verify_safepoint_unused(
1945         &self,
1946         inst: Inst,
1947         errors: &mut VerifierErrors,
1948     ) -> VerifierStepResult<()> {
1949         if let Some(isa) = self.isa {
1950             if !isa.flags().enable_safepoints() && self.func.dfg[inst].opcode() == Opcode::Safepoint
1951             {
1952                 return errors.fatal((
1953                     inst,
1954                     self.context(inst),
1955                     "safepoint instruction cannot be used when it is not enabled.",
1956                 ));
1957             }
1958         }
1959         Ok(())
1960     }
1961 
typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()>1962     fn typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
1963         self.func
1964             .signature
1965             .params
1966             .iter()
1967             .enumerate()
1968             .filter(|(_, &param)| param.value_type == types::INVALID)
1969             .for_each(|(i, _)| {
1970                 errors.report((
1971                     AnyEntity::Function,
1972                     format!("Parameter at position {} has an invalid type", i),
1973                 ));
1974             });
1975 
1976         self.func
1977             .signature
1978             .returns
1979             .iter()
1980             .enumerate()
1981             .filter(|(_, &ret)| ret.value_type == types::INVALID)
1982             .for_each(|(i, _)| {
1983                 errors.report((
1984                     AnyEntity::Function,
1985                     format!("Return value at position {} has an invalid type", i),
1986                 ))
1987             });
1988 
1989         if errors.has_error() {
1990             Err(())
1991         } else {
1992             Ok(())
1993         }
1994     }
1995 
run(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()>1996     pub fn run(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
1997         self.verify_global_values(errors)?;
1998         self.verify_heaps(errors)?;
1999         self.verify_tables(errors)?;
2000         self.verify_jump_tables(errors)?;
2001         self.typecheck_entry_block_params(errors)?;
2002         self.typecheck_function_signature(errors)?;
2003 
2004         for block in self.func.layout.blocks() {
2005             if self.func.layout.first_inst(block).is_none() {
2006                 return errors.fatal((block, format!("{} cannot be empty", block)));
2007             }
2008             for inst in self.func.layout.block_insts(block) {
2009                 self.block_integrity(block, inst, errors)?;
2010                 self.instruction_integrity(inst, errors)?;
2011                 self.verify_safepoint_unused(inst, errors)?;
2012                 self.typecheck(inst, errors)?;
2013                 self.verify_encoding(inst, errors)?;
2014                 self.immediate_constraints(inst, errors)?;
2015             }
2016 
2017             self.encodable_as_bb(block, errors)?;
2018         }
2019 
2020         verify_flags(self.func, &self.expected_cfg, self.isa, errors)?;
2021 
2022         if !errors.is_empty() {
2023             debug!(
2024                 "Found verifier errors in function:\n{}",
2025                 pretty_verifier_error(self.func, None, None, errors.clone())
2026             );
2027         }
2028 
2029         Ok(())
2030     }
2031 }
2032 
2033 #[cfg(test)]
2034 mod tests {
2035     use super::{Verifier, VerifierError, VerifierErrors};
2036     use crate::entity::EntityList;
2037     use crate::ir::instructions::{InstructionData, Opcode};
2038     use crate::ir::{types, AbiParam, Function};
2039     use crate::settings;
2040 
2041     macro_rules! assert_err_with_msg {
2042         ($e:expr, $msg:expr) => {
2043             match $e.0.get(0) {
2044                 None => panic!("Expected an error"),
2045                 Some(&VerifierError { ref message, .. }) => {
2046                     if !message.contains($msg) {
2047                         #[cfg(feature = "std")]
2048                         panic!(format!(
2049                             "'{}' did not contain the substring '{}'",
2050                             message, $msg
2051                         ));
2052                         #[cfg(not(feature = "std"))]
2053                         panic!("error message did not contain the expected substring");
2054                     }
2055                 }
2056             }
2057         };
2058     }
2059 
2060     #[test]
empty()2061     fn empty() {
2062         let func = Function::new();
2063         let flags = &settings::Flags::new(settings::builder());
2064         let verifier = Verifier::new(&func, flags.into());
2065         let mut errors = VerifierErrors::default();
2066 
2067         assert_eq!(verifier.run(&mut errors), Ok(()));
2068         assert!(errors.0.is_empty());
2069     }
2070 
2071     #[test]
bad_instruction_format()2072     fn bad_instruction_format() {
2073         let mut func = Function::new();
2074         let block0 = func.dfg.make_block();
2075         func.layout.append_block(block0);
2076         let nullary_with_bad_opcode = func.dfg.make_inst(InstructionData::UnaryImm {
2077             opcode: Opcode::F32const,
2078             imm: 0.into(),
2079         });
2080         func.layout.append_inst(nullary_with_bad_opcode, block0);
2081         func.layout.append_inst(
2082             func.dfg.make_inst(InstructionData::Jump {
2083                 opcode: Opcode::Jump,
2084                 destination: block0,
2085                 args: EntityList::default(),
2086             }),
2087             block0,
2088         );
2089         let flags = &settings::Flags::new(settings::builder());
2090         let verifier = Verifier::new(&func, flags.into());
2091         let mut errors = VerifierErrors::default();
2092 
2093         let _ = verifier.run(&mut errors);
2094 
2095         assert_err_with_msg!(errors, "instruction format");
2096     }
2097 
2098     #[test]
test_function_invalid_param()2099     fn test_function_invalid_param() {
2100         let mut func = Function::new();
2101         func.signature.params.push(AbiParam::new(types::INVALID));
2102 
2103         let mut errors = VerifierErrors::default();
2104         let flags = &settings::Flags::new(settings::builder());
2105         let verifier = Verifier::new(&func, flags.into());
2106 
2107         let _ = verifier.typecheck_function_signature(&mut errors);
2108         assert_err_with_msg!(errors, "Parameter at position 0 has an invalid type");
2109     }
2110 
2111     #[test]
test_function_invalid_return_value()2112     fn test_function_invalid_return_value() {
2113         let mut func = Function::new();
2114         func.signature.returns.push(AbiParam::new(types::INVALID));
2115 
2116         let mut errors = VerifierErrors::default();
2117         let flags = &settings::Flags::new(settings::builder());
2118         let verifier = Verifier::new(&func, flags.into());
2119 
2120         let _ = verifier.typecheck_function_signature(&mut errors);
2121         assert_err_with_msg!(errors, "Return value at position 0 has an invalid type");
2122     }
2123 
2124     #[test]
test_printing_contextual_errors()2125     fn test_printing_contextual_errors() {
2126         // Build function.
2127         let mut func = Function::new();
2128         let block0 = func.dfg.make_block();
2129         func.layout.append_block(block0);
2130 
2131         // Build instruction: v0, v1 = iconst 42
2132         let inst = func.dfg.make_inst(InstructionData::UnaryImm {
2133             opcode: Opcode::Iconst,
2134             imm: 42.into(),
2135         });
2136         func.dfg.append_result(inst, types::I32);
2137         func.dfg.append_result(inst, types::I32);
2138         func.layout.append_inst(inst, block0);
2139 
2140         // Setup verifier.
2141         let mut errors = VerifierErrors::default();
2142         let flags = &settings::Flags::new(settings::builder());
2143         let verifier = Verifier::new(&func, flags.into());
2144 
2145         // Now the error message, when printed, should contain the instruction sequence causing the
2146         // error (i.e. v0, v1 = iconst.i32 42) and not only its entity value (i.e. inst0)
2147         let _ = verifier.typecheck_results(inst, types::I32, &mut errors);
2148         assert_eq!(
2149             format!("{}", errors.0[0]),
2150             "inst0 (v0, v1 = iconst.i32 42): has more result values than expected"
2151         )
2152     }
2153 
2154     #[test]
test_empty_block()2155     fn test_empty_block() {
2156         let mut func = Function::new();
2157         let block0 = func.dfg.make_block();
2158         func.layout.append_block(block0);
2159 
2160         let flags = &settings::Flags::new(settings::builder());
2161         let verifier = Verifier::new(&func, flags.into());
2162         let mut errors = VerifierErrors::default();
2163         let _ = verifier.run(&mut errors);
2164 
2165         assert_err_with_msg!(errors, "block0 cannot be empty");
2166     }
2167 }
2168