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