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