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