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