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