1use crate::dbg::DisplayList;
61use crate::dominator_tree::DominatorTree;
62use crate::entity::SparseSet;
63use crate::flowgraph::{BlockPredecessor, ControlFlowGraph};
64use crate::ir::entities::AnyEntity;
65use crate::ir::instructions::{CallInfo, InstructionFormat, ResolvedConstraint};
66use crate::ir::{self, ArgumentExtension};
67use crate::ir::{
68 types, ArgumentPurpose, Block, Constant, DynamicStackSlot, FuncRef, Function, GlobalValue,
69 Inst, JumpTable, MemFlags, Opcode, SigRef, StackSlot, Type, Value, ValueDef, ValueList,
70};
71use crate::isa::TargetIsa;
72use crate::iterators::IteratorExtras;
73use crate::print_errors::pretty_verifier_error;
74use crate::settings::FlagsOrIsa;
75use crate::timing;
76use alloc::collections::BTreeSet;
77use alloc::string::{String, ToString};
78use alloc::vec::Vec;
79use core::cmp::Ordering;
80use core::fmt::{self, Display, Formatter};
81
82#[derive(Debug, PartialEq, Eq, Clone)]
84pub struct VerifierError {
85 pub location: AnyEntity,
87 pub context: Option<String>,
90 pub message: String,
92}
93
94impl std::error::Error for VerifierError {}
97
98impl 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
107impl<L, C, M> From<(L, C, M)> for VerifierError
118where
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
133impl<L, M> From<(L, M)> for VerifierError
137where
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
151pub type VerifierStepResult<T> = Result<T, ()>;
162
163pub type VerifierResult<T> = Result<T, VerifierErrors>;
168
169#[derive(Debug, Default, PartialEq, Eq, Clone)]
171pub struct VerifierErrors(pub Vec<VerifierError>);
172
173impl std::error::Error for VerifierErrors {}
176
177impl VerifierErrors {
178 #[inline]
180 pub fn new() -> Self {
181 Self(Vec::new())
182 }
183
184 #[inline]
186 pub fn is_empty(&self) -> bool {
187 self.0.is_empty()
188 }
189
190 #[inline]
192 pub fn has_error(&self) -> bool {
193 !self.0.is_empty()
194 }
195
196 #[inline]
199 pub fn as_result(&self) -> VerifierStepResult<()> {
200 if self.is_empty() {
201 Ok(())
202 } else {
203 Err(())
204 }
205 }
206
207 pub fn report(&mut self, error: impl Into<VerifierError>) {
209 self.0.push(error.into());
210 }
211
212 pub fn fatal(&mut self, error: impl Into<VerifierError>) -> VerifierStepResult<()> {
214 self.report(error);
215 Err(())
216 }
217
218 pub fn nonfatal(&mut self, error: impl Into<VerifierError>) -> VerifierStepResult<()> {
220 self.report(error);
221 Ok(())
222 }
223}
224
225impl From<Vec<VerifierError>> for VerifierErrors {
226 fn from(v: Vec<VerifierError>) -> Self {
227 Self(v)
228 }
229}
230
231impl Into<Vec<VerifierError>> for VerifierErrors {
232 fn into(self) -> Vec<VerifierError> {
233 self.0
234 }
235}
236
237impl 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
247impl 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
256pub 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
273pub 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
293struct Verifier<'a> {
294 func: &'a Function,
295 expected_cfg: ControlFlowGraph,
296 expected_domtree: DominatorTree,
297 isa: Option<&'a dyn TargetIsa>,
298}
299
300impl<'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 #[inline]
314 fn context(&self, inst: Inst) -> String {
315 self.func.dfg.display_inst(inst).to_string()
316 }
317
318 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 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 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 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 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 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 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 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 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 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 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 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 match dfg.value_def(v) {
896 ValueDef::Result(def_inst, _) => {
897 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 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 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 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 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 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 }
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 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 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 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 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!("has an invalid controlling type {}", ctrl_type),
1179 ));
1180 }
1181
1182 ctrl_type
1183 } else {
1184 types::INVALID
1187 };
1188
1189 let _ = self.typecheck_results(inst, ctrl_type, errors);
1191 let _ = self.typecheck_fixed_args(inst, ctrl_type, errors);
1192 let _ = self.typecheck_variable_args(inst, errors);
1193 let _ = self.typecheck_return(inst, errors);
1194 let _ = self.typecheck_special(inst, errors);
1195
1196 Ok(())
1197 }
1198
1199 fn typecheck_results(
1200 &self,
1201 inst: Inst,
1202 ctrl_type: Type,
1203 errors: &mut VerifierErrors,
1204 ) -> VerifierStepResult<()> {
1205 let mut i = 0;
1206 for &result in self.func.dfg.inst_results(inst) {
1207 let result_type = self.func.dfg.value_type(result);
1208 let expected_type = self.func.dfg.compute_result_type(inst, i, ctrl_type);
1209 if let Some(expected_type) = expected_type {
1210 if result_type != expected_type {
1211 errors.report((
1212 inst,
1213 self.context(inst),
1214 format!(
1215 "expected result {} ({}) to have type {}, found {}",
1216 i, result, expected_type, result_type
1217 ),
1218 ));
1219 }
1220 } else {
1221 return errors.nonfatal((
1222 inst,
1223 self.context(inst),
1224 "has more result values than expected",
1225 ));
1226 }
1227 i += 1;
1228 }
1229
1230 if self.func.dfg.compute_result_type(inst, i, ctrl_type) != None {
1232 return errors.nonfatal((
1233 inst,
1234 self.context(inst),
1235 "has fewer result values than expected",
1236 ));
1237 }
1238 Ok(())
1239 }
1240
1241 fn typecheck_fixed_args(
1242 &self,
1243 inst: Inst,
1244 ctrl_type: Type,
1245 errors: &mut VerifierErrors,
1246 ) -> VerifierStepResult<()> {
1247 let constraints = self.func.dfg.insts[inst].opcode().constraints();
1248
1249 for (i, &arg) in self.func.dfg.inst_fixed_args(inst).iter().enumerate() {
1250 let arg_type = self.func.dfg.value_type(arg);
1251 match constraints.value_argument_constraint(i, ctrl_type) {
1252 ResolvedConstraint::Bound(expected_type) => {
1253 if arg_type != expected_type {
1254 errors.report((
1255 inst,
1256 self.context(inst),
1257 format!(
1258 "arg {} ({}) has type {}, expected {}",
1259 i, arg, arg_type, expected_type
1260 ),
1261 ));
1262 }
1263 }
1264 ResolvedConstraint::Free(type_set) => {
1265 if !type_set.contains(arg_type) {
1266 errors.report((
1267 inst,
1268 self.context(inst),
1269 format!(
1270 "arg {} ({}) with type {} failed to satisfy type set {:?}",
1271 i, arg, arg_type, type_set
1272 ),
1273 ));
1274 }
1275 }
1276 }
1277 }
1278 Ok(())
1279 }
1280
1281 fn typecheck_variable_args(
1284 &self,
1285 inst: Inst,
1286 errors: &mut VerifierErrors,
1287 ) -> VerifierStepResult<()> {
1288 match &self.func.dfg.insts[inst] {
1289 ir::InstructionData::Jump { destination, .. } => {
1290 self.typecheck_block_call(inst, destination, errors)?;
1291 }
1292 ir::InstructionData::Brif {
1293 blocks: [block_then, block_else],
1294 ..
1295 } => {
1296 self.typecheck_block_call(inst, block_then, errors)?;
1297 self.typecheck_block_call(inst, block_else, errors)?;
1298 }
1299 ir::InstructionData::BranchTable { table, .. } => {
1300 for block in self.func.stencil.dfg.jump_tables[*table].all_branches() {
1301 self.typecheck_block_call(inst, block, errors)?;
1302 }
1303 }
1304 inst => debug_assert!(!inst.opcode().is_branch()),
1305 }
1306
1307 match self.func.dfg.insts[inst].analyze_call(&self.func.dfg.value_lists) {
1308 CallInfo::Direct(func_ref, args) => {
1309 let sig_ref = self.func.dfg.ext_funcs[func_ref].signature;
1310 let arg_types = self.func.dfg.signatures[sig_ref]
1311 .params
1312 .iter()
1313 .map(|a| a.value_type);
1314 self.typecheck_variable_args_iterator(inst, arg_types, args, errors)?;
1315 }
1316 CallInfo::Indirect(sig_ref, args) => {
1317 let arg_types = self.func.dfg.signatures[sig_ref]
1318 .params
1319 .iter()
1320 .map(|a| a.value_type);
1321 self.typecheck_variable_args_iterator(inst, arg_types, args, errors)?;
1322 }
1323 CallInfo::NotACall => {}
1324 }
1325 Ok(())
1326 }
1327
1328 fn typecheck_block_call(
1329 &self,
1330 inst: Inst,
1331 block: &ir::BlockCall,
1332 errors: &mut VerifierErrors,
1333 ) -> VerifierStepResult<()> {
1334 let pool = &self.func.dfg.value_lists;
1335 let iter = self
1336 .func
1337 .dfg
1338 .block_params(block.block(pool))
1339 .iter()
1340 .map(|&v| self.func.dfg.value_type(v));
1341 let args = block.args_slice(pool);
1342 self.typecheck_variable_args_iterator(inst, iter, args, errors)
1343 }
1344
1345 fn typecheck_variable_args_iterator<I: Iterator<Item = Type>>(
1346 &self,
1347 inst: Inst,
1348 iter: I,
1349 variable_args: &[Value],
1350 errors: &mut VerifierErrors,
1351 ) -> VerifierStepResult<()> {
1352 let mut i = 0;
1353
1354 for expected_type in iter {
1355 if i >= variable_args.len() {
1356 i += 1;
1358 continue;
1359 }
1360 let arg = variable_args[i];
1361 let arg_type = self.func.dfg.value_type(arg);
1362 if expected_type != arg_type {
1363 errors.report((
1364 inst,
1365 self.context(inst),
1366 format!(
1367 "arg {} ({}) has type {}, expected {}",
1368 i, variable_args[i], arg_type, expected_type
1369 ),
1370 ));
1371 }
1372 i += 1;
1373 }
1374 if i != variable_args.len() {
1375 return errors.nonfatal((
1376 inst,
1377 self.context(inst),
1378 format!(
1379 "mismatched argument count for `{}`: got {}, expected {}",
1380 self.func.dfg.display_inst(inst),
1381 variable_args.len(),
1382 i,
1383 ),
1384 ));
1385 }
1386 Ok(())
1387 }
1388
1389 fn typecheck_return(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
1390 match self.func.dfg.insts[inst] {
1391 ir::InstructionData::MultiAry {
1392 opcode: Opcode::Return,
1393 args,
1394 } => {
1395 let types = args
1396 .as_slice(&self.func.dfg.value_lists)
1397 .iter()
1398 .map(|v| self.func.dfg.value_type(*v));
1399 self.typecheck_return_types(
1400 inst,
1401 types,
1402 errors,
1403 "arguments of return must match function signature",
1404 )?;
1405 }
1406 ir::InstructionData::Call {
1407 opcode: Opcode::ReturnCall,
1408 func_ref,
1409 ..
1410 } => {
1411 let sig_ref = self.func.dfg.ext_funcs[func_ref].signature;
1412 self.typecheck_tail_call(inst, sig_ref, errors)?;
1413 }
1414 ir::InstructionData::CallIndirect {
1415 opcode: Opcode::ReturnCallIndirect,
1416 sig_ref,
1417 ..
1418 } => {
1419 self.typecheck_tail_call(inst, sig_ref, errors)?;
1420 }
1421 inst => debug_assert!(!inst.opcode().is_return()),
1422 }
1423 Ok(())
1424 }
1425
1426 fn typecheck_tail_call(
1427 &self,
1428 inst: Inst,
1429 sig_ref: SigRef,
1430 errors: &mut VerifierErrors,
1431 ) -> VerifierStepResult<()> {
1432 let signature = &self.func.dfg.signatures[sig_ref];
1433 let cc = signature.call_conv;
1434 if !cc.supports_tail_calls() {
1435 errors.report((
1436 inst,
1437 self.context(inst),
1438 format!("calling convention `{cc}` does not support tail calls"),
1439 ));
1440 }
1441 if cc != self.func.signature.call_conv {
1442 errors.report((
1443 inst,
1444 self.context(inst),
1445 "callee's calling convention must match caller",
1446 ));
1447 }
1448 let types = signature.returns.iter().map(|param| param.value_type);
1449 self.typecheck_return_types(inst, types, errors, "results of callee must match caller")?;
1450 Ok(())
1451 }
1452
1453 fn typecheck_return_types(
1454 &self,
1455 inst: Inst,
1456 actual_types: impl ExactSizeIterator<Item = Type>,
1457 errors: &mut VerifierErrors,
1458 message: &str,
1459 ) -> VerifierStepResult<()> {
1460 let expected_types = &self.func.signature.returns;
1461 if actual_types.len() != expected_types.len() {
1462 return errors.nonfatal((inst, self.context(inst), message));
1463 }
1464 for (i, (actual_type, &expected_type)) in actual_types.zip(expected_types).enumerate() {
1465 if actual_type != expected_type.value_type {
1466 errors.report((
1467 inst,
1468 self.context(inst),
1469 format!(
1470 "result {i} has type {actual_type}, must match function signature of \
1471 {expected_type}"
1472 ),
1473 ));
1474 }
1475 }
1476 Ok(())
1477 }
1478
1479 fn typecheck_special(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
1482 match self.func.dfg.insts[inst] {
1483 ir::InstructionData::TableAddr { table, arg, .. } => {
1484 let index_type = self.func.dfg.value_type(arg);
1485 let table_index_type = self.func.tables[table].index_type;
1486 if index_type != table_index_type {
1487 return errors.nonfatal((
1488 inst,
1489 self.context(inst),
1490 format!(
1491 "index type {} differs from table index type {}",
1492 index_type, table_index_type,
1493 ),
1494 ));
1495 }
1496 }
1497 ir::InstructionData::UnaryGlobalValue { global_value, .. } => {
1498 if let Some(isa) = self.isa {
1499 let inst_type = self.func.dfg.value_type(self.func.dfg.first_result(inst));
1500 let global_type = self.func.global_values[global_value].global_type(isa);
1501 if inst_type != global_type {
1502 return errors.nonfatal((
1503 inst, self.context(inst),
1504 format!(
1505 "global_value instruction with type {} references global value with type {}",
1506 inst_type, global_type
1507 )),
1508 );
1509 }
1510 }
1511 }
1512 _ => {}
1513 }
1514 Ok(())
1515 }
1516
1517 fn cfg_integrity(
1518 &self,
1519 cfg: &ControlFlowGraph,
1520 errors: &mut VerifierErrors,
1521 ) -> VerifierStepResult<()> {
1522 let mut expected_succs = BTreeSet::<Block>::new();
1523 let mut got_succs = BTreeSet::<Block>::new();
1524 let mut expected_preds = BTreeSet::<Inst>::new();
1525 let mut got_preds = BTreeSet::<Inst>::new();
1526
1527 for block in self.func.layout.blocks() {
1528 expected_succs.extend(self.expected_cfg.succ_iter(block));
1529 got_succs.extend(cfg.succ_iter(block));
1530
1531 let missing_succs: Vec<Block> =
1532 expected_succs.difference(&got_succs).cloned().collect();
1533 if !missing_succs.is_empty() {
1534 errors.report((
1535 block,
1536 format!("cfg lacked the following successor(s) {:?}", missing_succs),
1537 ));
1538 continue;
1539 }
1540
1541 let excess_succs: Vec<Block> = got_succs.difference(&expected_succs).cloned().collect();
1542 if !excess_succs.is_empty() {
1543 errors.report((
1544 block,
1545 format!("cfg had unexpected successor(s) {:?}", excess_succs),
1546 ));
1547 continue;
1548 }
1549
1550 expected_preds.extend(
1551 self.expected_cfg
1552 .pred_iter(block)
1553 .map(|BlockPredecessor { inst, .. }| inst),
1554 );
1555 got_preds.extend(
1556 cfg.pred_iter(block)
1557 .map(|BlockPredecessor { inst, .. }| inst),
1558 );
1559
1560 let missing_preds: Vec<Inst> = expected_preds.difference(&got_preds).cloned().collect();
1561 if !missing_preds.is_empty() {
1562 errors.report((
1563 block,
1564 format!(
1565 "cfg lacked the following predecessor(s) {:?}",
1566 missing_preds
1567 ),
1568 ));
1569 continue;
1570 }
1571
1572 let excess_preds: Vec<Inst> = got_preds.difference(&expected_preds).cloned().collect();
1573 if !excess_preds.is_empty() {
1574 errors.report((
1575 block,
1576 format!("cfg had unexpected predecessor(s) {:?}", excess_preds),
1577 ));
1578 continue;
1579 }
1580
1581 expected_succs.clear();
1582 got_succs.clear();
1583 expected_preds.clear();
1584 got_preds.clear();
1585 }
1586 errors.as_result()
1587 }
1588
1589 fn immediate_constraints(
1590 &self,
1591 inst: Inst,
1592 errors: &mut VerifierErrors,
1593 ) -> VerifierStepResult<()> {
1594 let inst_data = &self.func.dfg.insts[inst];
1595
1596 match *inst_data {
1597 ir::InstructionData::Store { flags, .. } => {
1598 if flags.readonly() {
1599 errors.fatal((
1600 inst,
1601 self.context(inst),
1602 "A store instruction cannot have the `readonly` MemFlag",
1603 ))
1604 } else {
1605 Ok(())
1606 }
1607 }
1608 ir::InstructionData::BinaryImm8 {
1609 opcode: ir::instructions::Opcode::Extractlane,
1610 imm: lane,
1611 arg,
1612 ..
1613 }
1614 | ir::InstructionData::TernaryImm8 {
1615 opcode: ir::instructions::Opcode::Insertlane,
1616 imm: lane,
1617 args: [arg, _],
1618 ..
1619 } => {
1620 let ty = self.func.dfg.value_type(arg);
1623 if lane as u32 >= ty.lane_count() {
1624 errors.fatal((
1625 inst,
1626 self.context(inst),
1627 format!("The lane {} does not index into the type {}", lane, ty,),
1628 ))
1629 } else {
1630 Ok(())
1631 }
1632 }
1633 ir::InstructionData::Shuffle {
1634 opcode: ir::instructions::Opcode::Shuffle,
1635 imm,
1636 ..
1637 } => {
1638 let imm = self.func.dfg.immediates.get(imm).unwrap().as_slice();
1639 if imm.len() != 16 {
1640 errors.fatal((
1641 inst,
1642 self.context(inst),
1643 format!("the shuffle immediate wasn't 16-bytes long"),
1644 ))
1645 } else if let Some(i) = imm.iter().find(|i| **i >= 32) {
1646 errors.fatal((
1647 inst,
1648 self.context(inst),
1649 format!("shuffle immediate index {i} is larger than the maximum 31"),
1650 ))
1651 } else {
1652 Ok(())
1653 }
1654 }
1655 _ => Ok(()),
1656 }
1657 }
1658
1659 fn typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
1660 let params = self
1661 .func
1662 .signature
1663 .params
1664 .iter()
1665 .enumerate()
1666 .map(|p| (true, p));
1667 let returns = self
1668 .func
1669 .signature
1670 .returns
1671 .iter()
1672 .enumerate()
1673 .map(|p| (false, p));
1674
1675 for (is_argument, (i, param)) in params.chain(returns) {
1676 let is_return = !is_argument;
1677 let item = if is_argument {
1678 "Parameter"
1679 } else {
1680 "Return value"
1681 };
1682
1683 if param.value_type == types::INVALID {
1684 errors.report((
1685 AnyEntity::Function,
1686 format!("{item} at position {i} has an invalid type"),
1687 ));
1688 }
1689
1690 if let ArgumentPurpose::StructArgument(_) = param.purpose {
1691 if is_return {
1692 errors.report((
1693 AnyEntity::Function,
1694 format!("{item} at position {i} can't be an struct argument"),
1695 ))
1696 }
1697 }
1698
1699 let ty_allows_extension = param.value_type.is_int();
1700 let has_extension = param.extension != ArgumentExtension::None;
1701 if !ty_allows_extension && has_extension {
1702 errors.report((
1703 AnyEntity::Function,
1704 format!(
1705 "{} at position {} has invalid extension {:?}",
1706 item, i, param.extension
1707 ),
1708 ));
1709 }
1710 }
1711
1712 if errors.has_error() {
1713 Err(())
1714 } else {
1715 Ok(())
1716 }
1717 }
1718
1719 pub fn run(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
1720 self.verify_global_values(errors)?;
1721 self.verify_tables(errors)?;
1722 self.typecheck_entry_block_params(errors)?;
1723 self.check_entry_not_cold(errors)?;
1724 self.typecheck_function_signature(errors)?;
1725
1726 for block in self.func.layout.blocks() {
1727 if self.func.layout.first_inst(block).is_none() {
1728 return errors.fatal((block, format!("{} cannot be empty", block)));
1729 }
1730 for inst in self.func.layout.block_insts(block) {
1731 self.block_integrity(block, inst, errors)?;
1732 self.instruction_integrity(inst, errors)?;
1733 self.typecheck(inst, errors)?;
1734 self.immediate_constraints(inst, errors)?;
1735 }
1736
1737 self.encodable_as_bb(block, errors)?;
1738 }
1739
1740 if !errors.is_empty() {
1741 log::warn!(
1742 "Found verifier errors in function:\n{}",
1743 pretty_verifier_error(self.func, None, errors.clone())
1744 );
1745 }
1746
1747 Ok(())
1748 }
1749}
1750
1751#[cfg(test)]
1752mod tests {
1753 use super::{Verifier, VerifierError, VerifierErrors};
1754 use crate::ir::instructions::{InstructionData, Opcode};
1755 use crate::ir::{types, AbiParam, Function};
1756 use crate::settings;
1757
1758 macro_rules! assert_err_with_msg {
1759 ($e:expr, $msg:expr) => {
1760 match $e.0.get(0) {
1761 None => panic!("Expected an error"),
1762 Some(&VerifierError { ref message, .. }) => {
1763 if !message.contains($msg) {
1764 #[cfg(feature = "std")]
1765 panic!("'{}' did not contain the substring '{}'", message, $msg);
1766 #[cfg(not(feature = "std"))]
1767 panic!("error message did not contain the expected substring");
1768 }
1769 }
1770 }
1771 };
1772 }
1773
1774 #[test]
1775 fn empty() {
1776 let func = Function::new();
1777 let flags = &settings::Flags::new(settings::builder());
1778 let verifier = Verifier::new(&func, flags.into());
1779 let mut errors = VerifierErrors::default();
1780
1781 assert_eq!(verifier.run(&mut errors), Ok(()));
1782 assert!(errors.0.is_empty());
1783 }
1784
1785 #[test]
1786 fn bad_instruction_format() {
1787 let mut func = Function::new();
1788 let block0 = func.dfg.make_block();
1789 func.layout.append_block(block0);
1790 let nullary_with_bad_opcode = func.dfg.make_inst(InstructionData::UnaryImm {
1791 opcode: Opcode::F32const,
1792 imm: 0.into(),
1793 });
1794 func.layout.append_inst(nullary_with_bad_opcode, block0);
1795 let destination = func.dfg.block_call(block0, &[]);
1796 func.stencil.layout.append_inst(
1797 func.stencil.dfg.make_inst(InstructionData::Jump {
1798 opcode: Opcode::Jump,
1799 destination,
1800 }),
1801 block0,
1802 );
1803 let flags = &settings::Flags::new(settings::builder());
1804 let verifier = Verifier::new(&func, flags.into());
1805 let mut errors = VerifierErrors::default();
1806
1807 let _ = verifier.run(&mut errors);
1808
1809 assert_err_with_msg!(errors, "instruction format");
1810 }
1811
1812 #[test]
1813 fn test_function_invalid_param() {
1814 let mut func = Function::new();
1815 func.signature.params.push(AbiParam::new(types::INVALID));
1816
1817 let mut errors = VerifierErrors::default();
1818 let flags = &settings::Flags::new(settings::builder());
1819 let verifier = Verifier::new(&func, flags.into());
1820
1821 let _ = verifier.typecheck_function_signature(&mut errors);
1822 assert_err_with_msg!(errors, "Parameter at position 0 has an invalid type");
1823 }
1824
1825 #[test]
1826 fn test_function_invalid_return_value() {
1827 let mut func = Function::new();
1828 func.signature.returns.push(AbiParam::new(types::INVALID));
1829
1830 let mut errors = VerifierErrors::default();
1831 let flags = &settings::Flags::new(settings::builder());
1832 let verifier = Verifier::new(&func, flags.into());
1833
1834 let _ = verifier.typecheck_function_signature(&mut errors);
1835 assert_err_with_msg!(errors, "Return value at position 0 has an invalid type");
1836 }
1837
1838 #[test]
1839 fn test_printing_contextual_errors() {
1840 let mut func = Function::new();
1842 let block0 = func.dfg.make_block();
1843 func.layout.append_block(block0);
1844
1845 let inst = func.dfg.make_inst(InstructionData::UnaryImm {
1847 opcode: Opcode::Iconst,
1848 imm: 42.into(),
1849 });
1850 func.dfg.append_result(inst, types::I32);
1851 func.dfg.append_result(inst, types::I32);
1852 func.layout.append_inst(inst, block0);
1853
1854 let mut errors = VerifierErrors::default();
1856 let flags = &settings::Flags::new(settings::builder());
1857 let verifier = Verifier::new(&func, flags.into());
1858
1859 let _ = verifier.typecheck_results(inst, types::I32, &mut errors);
1862 assert_eq!(
1863 format!("{}", errors.0[0]),
1864 "inst0 (v0, v1 = iconst.i32 42): has more result values than expected"
1865 )
1866 }
1867
1868 #[test]
1869 fn test_empty_block() {
1870 let mut func = Function::new();
1871 let block0 = func.dfg.make_block();
1872 func.layout.append_block(block0);
1873
1874 let flags = &settings::Flags::new(settings::builder());
1875 let verifier = Verifier::new(&func, flags.into());
1876 let mut errors = VerifierErrors::default();
1877 let _ = verifier.run(&mut errors);
1878
1879 assert_err_with_msg!(errors, "block0 cannot be empty");
1880 }
1881}