1747ad3c4Slazypassion //! A verifier for ensuring that functions are well formed.
2747ad3c4Slazypassion //! It verifies:
3747ad3c4Slazypassion //!
4832666c4SRyan Hunt //! block integrity
5747ad3c4Slazypassion //!
6832666c4SRyan Hunt //! - All instructions reached from the `block_insts` iterator must belong to
7832666c4SRyan Hunt //! the block as reported by `inst_block()`.
8832666c4SRyan Hunt //! - Every block must end in a terminator instruction, and no other instruction
9747ad3c4Slazypassion //! can be a terminator.
10832666c4SRyan Hunt //! - Every value in the `block_params` iterator belongs to the block as reported by `value_block`.
11747ad3c4Slazypassion //!
12747ad3c4Slazypassion //! Instruction integrity
13747ad3c4Slazypassion //!
14747ad3c4Slazypassion //! - The instruction format must match the opcode.
15747ad3c4Slazypassion //! - All result values must be created for multi-valued instructions.
16832666c4SRyan Hunt //! - All referenced entities must exist. (Values, blocks, stack slots, ...)
17747ad3c4Slazypassion //! - Instructions must not reference (eg. branch to) the entry block.
18747ad3c4Slazypassion //!
19747ad3c4Slazypassion //! SSA form
20747ad3c4Slazypassion //!
21747ad3c4Slazypassion //! - Values must be defined by an instruction that exists and that is inserted in
2207f335dcSRyan Hunt //! a block, or be an argument of an existing block.
23747ad3c4Slazypassion //! - Values used by an instruction must dominate the instruction.
24747ad3c4Slazypassion //!
25747ad3c4Slazypassion //! Control flow graph and dominator tree integrity:
26747ad3c4Slazypassion //!
27832666c4SRyan Hunt //! - All predecessors in the CFG must be branches to the block.
2807f335dcSRyan Hunt //! - All branches to a block must be present in the CFG.
29747ad3c4Slazypassion //! - A recomputed dominator tree is identical to the existing one.
30953f83e6SChris Fallin //! - The entry block must not be a cold block.
31747ad3c4Slazypassion //!
32747ad3c4Slazypassion //! Type checking
33747ad3c4Slazypassion //!
34747ad3c4Slazypassion //! - Compare input and output values against the opcode's type constraints.
35747ad3c4Slazypassion //! For polymorphic opcodes, determine the controlling type variable first.
36832666c4SRyan Hunt //! - Branches and jumps must pass arguments to destination blocks that match the
37747ad3c4Slazypassion //! expected types exactly. The number of arguments must match.
38832666c4SRyan Hunt //! - All blocks in a jump table must take no arguments.
39747ad3c4Slazypassion //! - Function calls are type checked against their signature.
40747ad3c4Slazypassion //! - The entry block must take arguments that match the signature of the current
41747ad3c4Slazypassion //! function.
42747ad3c4Slazypassion //! - All return instructions must have return value operands matching the current
43747ad3c4Slazypassion //! function signature.
44747ad3c4Slazypassion //!
45747ad3c4Slazypassion //! Global values
46747ad3c4Slazypassion //!
47747ad3c4Slazypassion //! - Detect cycles in global values.
48747ad3c4Slazypassion //! - Detect use of 'vmctx' global value when no corresponding parameter is defined.
49747ad3c4Slazypassion //!
501ced3e8eSChris Fallin //! Memory types
511ced3e8eSChris Fallin //!
521ced3e8eSChris Fallin //! - Ensure that struct fields are in offset order.
531ced3e8eSChris Fallin //! - Ensure that struct fields are completely within the overall
541ced3e8eSChris Fallin //! struct size, and do not overlap.
551ced3e8eSChris Fallin //!
56747ad3c4Slazypassion //! TODO:
57747ad3c4Slazypassion //! Ad hoc checking
58747ad3c4Slazypassion //!
59747ad3c4Slazypassion //! - Stack slot loads and stores must be in-bounds.
60747ad3c4Slazypassion //! - Immediate constraints for certain opcodes, like `udiv_imm v3, 0`.
61747ad3c4Slazypassion //! - `Insertlane` and `extractlane` instructions have immediate lane numbers that must be in
62747ad3c4Slazypassion //! range for their polymorphic type.
63747ad3c4Slazypassion //! - Swizzle and shuffle instructions take a variable number of lane arguments. The number
64747ad3c4Slazypassion //! of arguments must match the destination type, and the lane indexes must be in range.
65747ad3c4Slazypassion
66747ad3c4Slazypassion use crate::dbg::DisplayList;
67747ad3c4Slazypassion use crate::dominator_tree::DominatorTree;
68747ad3c4Slazypassion use crate::entity::SparseSet;
69832666c4SRyan Hunt use crate::flowgraph::{BlockPredecessor, ControlFlowGraph};
70747ad3c4Slazypassion use crate::ir::entities::AnyEntity;
71c8a6adf8STrevor Elliott use crate::ir::instructions::{CallInfo, InstructionFormat, ResolvedConstraint};
7294ec88eaSChris Fallin use crate::ir::{self, ArgumentExtension, BlockArg, ExceptionTable};
73747ad3c4Slazypassion use crate::ir::{
7490ac295eSAlex Crichton ArgumentPurpose, Block, Constant, DynamicStackSlot, FuncRef, Function, GlobalValue, Inst,
75*2f7dbd61SChris Fallin JumpTable, MemFlags, Opcode, SigRef, StackSlot, Type, Value, ValueDef, ValueList, types,
76747ad3c4Slazypassion };
77c3c2ee20SChris Fallin use crate::ir::{ExceptionTableItem, Signature};
78c3c2ee20SChris Fallin use crate::isa::{CallConv, TargetIsa};
79838f2f46SAndrew Brown use crate::print_errors::pretty_verifier_error;
80747ad3c4Slazypassion use crate::settings::FlagsOrIsa;
81747ad3c4Slazypassion use crate::timing;
8210e226f9Sbjorn3 use alloc::collections::BTreeSet;
83838f2f46SAndrew Brown use alloc::string::{String, ToString};
8410e226f9Sbjorn3 use alloc::vec::Vec;
85bae4ec64SBenjamin Bouvier use core::fmt::{self, Display, Formatter};
86c3c2ee20SChris Fallin use cranelift_entity::packed_option::ReservedValue;
87747ad3c4Slazypassion
88747ad3c4Slazypassion /// A verifier error.
8903fdbadfSbjorn3 #[derive(Debug, PartialEq, Eq, Clone)]
90747ad3c4Slazypassion pub struct VerifierError {
91747ad3c4Slazypassion /// The entity causing the verifier error.
92747ad3c4Slazypassion pub location: AnyEntity,
93838f2f46SAndrew Brown /// Optionally provide some context for the given location; e.g., for `inst42` provide
94838f2f46SAndrew Brown /// `Some("v3 = iconst.i32 0")` for more comprehensible errors.
95838f2f46SAndrew Brown pub context: Option<String>,
96747ad3c4Slazypassion /// The error message.
97747ad3c4Slazypassion pub message: String,
98747ad3c4Slazypassion }
99747ad3c4Slazypassion
10082f3ad4fSbjorn3 // This is manually implementing Error and Display instead of using thiserror to reduce the amount
10182f3ad4fSbjorn3 // of dependencies used by Cranelift.
1020889323aSSSD impl core::error::Error for VerifierError {}
10303fdbadfSbjorn3
10403fdbadfSbjorn3 impl Display for VerifierError {
fmt(&self, f: &mut Formatter) -> fmt::Result10503fdbadfSbjorn3 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
10603fdbadfSbjorn3 match &self.context {
10703fdbadfSbjorn3 None => write!(f, "{}: {}", self.location, self.message),
10803fdbadfSbjorn3 Some(context) => write!(f, "{} ({}): {}", self.location, context, self.message),
10903fdbadfSbjorn3 }
110838f2f46SAndrew Brown }
111838f2f46SAndrew Brown }
112838f2f46SAndrew Brown
1133e5f0393SAndrew Brown /// Convenience converter for making error-reporting less verbose.
1143e5f0393SAndrew Brown ///
1153e5f0393SAndrew Brown /// Converts a tuple of `(location, context, message)` to a `VerifierError`.
1163e5f0393SAndrew Brown /// ```
1173e5f0393SAndrew Brown /// use cranelift_codegen::verifier::VerifierErrors;
1183e5f0393SAndrew Brown /// use cranelift_codegen::ir::Inst;
1193e5f0393SAndrew Brown /// let mut errors = VerifierErrors::new();
1203e5f0393SAndrew Brown /// errors.report((Inst::from_u32(42), "v3 = iadd v1, v2", "iadd cannot be used with values of this type"));
1213e5f0393SAndrew Brown /// // note the double parenthenses to use this syntax
1223e5f0393SAndrew Brown /// ```
1233e5f0393SAndrew Brown impl<L, C, M> From<(L, C, M)> for VerifierError
1243e5f0393SAndrew Brown where
1253e5f0393SAndrew Brown L: Into<AnyEntity>,
1263e5f0393SAndrew Brown C: Into<String>,
1273e5f0393SAndrew Brown M: Into<String>,
1283e5f0393SAndrew Brown {
from(items: (L, C, M)) -> Self1293e5f0393SAndrew Brown fn from(items: (L, C, M)) -> Self {
1303e5f0393SAndrew Brown let (location, context, message) = items;
1313e5f0393SAndrew Brown Self {
1323e5f0393SAndrew Brown location: location.into(),
1333e5f0393SAndrew Brown context: Some(context.into()),
1343e5f0393SAndrew Brown message: message.into(),
1353e5f0393SAndrew Brown }
1363e5f0393SAndrew Brown }
1373e5f0393SAndrew Brown }
1383e5f0393SAndrew Brown
1393e5f0393SAndrew Brown /// Convenience converter for making error-reporting less verbose.
1403e5f0393SAndrew Brown ///
1413e5f0393SAndrew Brown /// Same as above but without `context`.
1423e5f0393SAndrew Brown impl<L, M> From<(L, M)> for VerifierError
1433e5f0393SAndrew Brown where
1443e5f0393SAndrew Brown L: Into<AnyEntity>,
1453e5f0393SAndrew Brown M: Into<String>,
1463e5f0393SAndrew Brown {
from(items: (L, M)) -> Self1473e5f0393SAndrew Brown fn from(items: (L, M)) -> Self {
1483e5f0393SAndrew Brown let (location, message) = items;
1493e5f0393SAndrew Brown Self {
1503e5f0393SAndrew Brown location: location.into(),
1513e5f0393SAndrew Brown context: None,
1523e5f0393SAndrew Brown message: message.into(),
1533e5f0393SAndrew Brown }
1543e5f0393SAndrew Brown }
1553e5f0393SAndrew Brown }
1563e5f0393SAndrew Brown
157747ad3c4Slazypassion /// Result of a step in the verification process.
158747ad3c4Slazypassion ///
159220139b0Sedoardo marangoni /// Functions that return `VerifierStepResult` should also take a
160747ad3c4Slazypassion /// mutable reference to `VerifierErrors` as argument in order to report
161747ad3c4Slazypassion /// errors.
162747ad3c4Slazypassion ///
163747ad3c4Slazypassion /// Here, `Ok` represents a step that **did not lead to a fatal error**,
164747ad3c4Slazypassion /// meaning that the verification process may continue. However, other (non-fatal)
165747ad3c4Slazypassion /// errors might have been reported through the previously mentioned `VerifierErrors`
166747ad3c4Slazypassion /// argument.
167220139b0Sedoardo marangoni pub type VerifierStepResult = Result<(), ()>;
168747ad3c4Slazypassion
169747ad3c4Slazypassion /// Result of a verification operation.
170747ad3c4Slazypassion ///
171220139b0Sedoardo marangoni /// Unlike `VerifierStepResult` which may be `Ok` while still having reported
172747ad3c4Slazypassion /// errors, this type always returns `Err` if an error (fatal or not) was reported.
173747ad3c4Slazypassion pub type VerifierResult<T> = Result<T, VerifierErrors>;
174747ad3c4Slazypassion
175747ad3c4Slazypassion /// List of verifier errors.
17603fdbadfSbjorn3 #[derive(Debug, Default, PartialEq, Eq, Clone)]
177747ad3c4Slazypassion pub struct VerifierErrors(pub Vec<VerifierError>);
178747ad3c4Slazypassion
17982f3ad4fSbjorn3 // This is manually implementing Error and Display instead of using thiserror to reduce the amount
18082f3ad4fSbjorn3 // of dependencies used by Cranelift.
1810889323aSSSD impl core::error::Error for VerifierErrors {}
18203fdbadfSbjorn3
183747ad3c4Slazypassion impl VerifierErrors {
184747ad3c4Slazypassion /// Return a new `VerifierErrors` struct.
185747ad3c4Slazypassion #[inline]
new() -> Self186747ad3c4Slazypassion pub fn new() -> Self {
1879f506692SPeter Huene Self(Vec::new())
188747ad3c4Slazypassion }
189747ad3c4Slazypassion
190747ad3c4Slazypassion /// Return whether no errors were reported.
191747ad3c4Slazypassion #[inline]
is_empty(&self) -> bool192747ad3c4Slazypassion pub fn is_empty(&self) -> bool {
193747ad3c4Slazypassion self.0.is_empty()
194747ad3c4Slazypassion }
195747ad3c4Slazypassion
196747ad3c4Slazypassion /// Return whether one or more errors were reported.
197747ad3c4Slazypassion #[inline]
has_error(&self) -> bool198747ad3c4Slazypassion pub fn has_error(&self) -> bool {
199747ad3c4Slazypassion !self.0.is_empty()
200747ad3c4Slazypassion }
201747ad3c4Slazypassion
202747ad3c4Slazypassion /// Return a `VerifierStepResult` that is fatal if at least one error was reported,
203747ad3c4Slazypassion /// and non-fatal otherwise.
204747ad3c4Slazypassion #[inline]
as_result(&self) -> VerifierStepResult205220139b0Sedoardo marangoni pub fn as_result(&self) -> VerifierStepResult {
20690ac295eSAlex Crichton if self.is_empty() { Ok(()) } else { Err(()) }
207747ad3c4Slazypassion }
2083e5f0393SAndrew Brown
2093e5f0393SAndrew Brown /// Report an error, adding it to the list of errors.
report(&mut self, error: impl Into<VerifierError>)2103e5f0393SAndrew Brown pub fn report(&mut self, error: impl Into<VerifierError>) {
2113e5f0393SAndrew Brown self.0.push(error.into());
2123e5f0393SAndrew Brown }
2133e5f0393SAndrew Brown
2143e5f0393SAndrew Brown /// Report a fatal error and return `Err`.
fatal(&mut self, error: impl Into<VerifierError>) -> VerifierStepResult215220139b0Sedoardo marangoni pub fn fatal(&mut self, error: impl Into<VerifierError>) -> VerifierStepResult {
2163e5f0393SAndrew Brown self.report(error);
2173e5f0393SAndrew Brown Err(())
2183e5f0393SAndrew Brown }
2193e5f0393SAndrew Brown
2203e5f0393SAndrew Brown /// Report a non-fatal error and return `Ok`.
nonfatal(&mut self, error: impl Into<VerifierError>) -> VerifierStepResult221220139b0Sedoardo marangoni pub fn nonfatal(&mut self, error: impl Into<VerifierError>) -> VerifierStepResult {
2223e5f0393SAndrew Brown self.report(error);
2233e5f0393SAndrew Brown Ok(())
2243e5f0393SAndrew Brown }
225747ad3c4Slazypassion }
226747ad3c4Slazypassion
227747ad3c4Slazypassion impl From<Vec<VerifierError>> for VerifierErrors {
from(v: Vec<VerifierError>) -> Self228747ad3c4Slazypassion fn from(v: Vec<VerifierError>) -> Self {
2299f506692SPeter Huene Self(v)
230747ad3c4Slazypassion }
231747ad3c4Slazypassion }
232747ad3c4Slazypassion
233d3e7548eSAlex Crichton impl From<VerifierErrors> for Vec<VerifierError> {
from(errors: VerifierErrors) -> Vec<VerifierError>234d3e7548eSAlex Crichton fn from(errors: VerifierErrors) -> Vec<VerifierError> {
235d3e7548eSAlex Crichton errors.0
236747ad3c4Slazypassion }
237747ad3c4Slazypassion }
238747ad3c4Slazypassion
239d3e7548eSAlex Crichton impl From<VerifierErrors> for VerifierResult<()> {
from(errors: VerifierErrors) -> VerifierResult<()>240d3e7548eSAlex Crichton fn from(errors: VerifierErrors) -> VerifierResult<()> {
241d3e7548eSAlex Crichton if errors.is_empty() {
242d3e7548eSAlex Crichton Ok(())
243d3e7548eSAlex Crichton } else {
244d3e7548eSAlex Crichton Err(errors)
245d3e7548eSAlex Crichton }
246747ad3c4Slazypassion }
247747ad3c4Slazypassion }
248747ad3c4Slazypassion
249747ad3c4Slazypassion impl Display for VerifierErrors {
fmt(&self, f: &mut Formatter) -> fmt::Result250747ad3c4Slazypassion fn fmt(&self, f: &mut Formatter) -> fmt::Result {
251747ad3c4Slazypassion for err in &self.0 {
252a0442ea0SHamir Mahal writeln!(f, "- {err}")?;
253747ad3c4Slazypassion }
254747ad3c4Slazypassion Ok(())
255747ad3c4Slazypassion }
256747ad3c4Slazypassion }
257747ad3c4Slazypassion
258747ad3c4Slazypassion /// Verify `func`.
verify_function<'a, FOI: Into<FlagsOrIsa<'a>>>( func: &Function, fisa: FOI, ) -> VerifierResult<()>259747ad3c4Slazypassion pub fn verify_function<'a, FOI: Into<FlagsOrIsa<'a>>>(
260747ad3c4Slazypassion func: &Function,
261747ad3c4Slazypassion fisa: FOI,
262747ad3c4Slazypassion ) -> VerifierResult<()> {
263747ad3c4Slazypassion let _tt = timing::verifier();
264747ad3c4Slazypassion let mut errors = VerifierErrors::default();
265747ad3c4Slazypassion let verifier = Verifier::new(func, fisa.into());
266747ad3c4Slazypassion let result = verifier.run(&mut errors);
267747ad3c4Slazypassion if errors.is_empty() {
268747ad3c4Slazypassion result.unwrap();
269747ad3c4Slazypassion Ok(())
270747ad3c4Slazypassion } else {
271747ad3c4Slazypassion Err(errors)
272747ad3c4Slazypassion }
273747ad3c4Slazypassion }
274747ad3c4Slazypassion
275747ad3c4Slazypassion /// Verify `func` after checking the integrity of associated context data structures `cfg` and
276747ad3c4Slazypassion /// `domtree`.
verify_context<'a, FOI: Into<FlagsOrIsa<'a>>>( func: &Function, cfg: &ControlFlowGraph, domtree: &DominatorTree, fisa: FOI, errors: &mut VerifierErrors, ) -> VerifierStepResult277747ad3c4Slazypassion pub fn verify_context<'a, FOI: Into<FlagsOrIsa<'a>>>(
278747ad3c4Slazypassion func: &Function,
279747ad3c4Slazypassion cfg: &ControlFlowGraph,
280747ad3c4Slazypassion domtree: &DominatorTree,
281747ad3c4Slazypassion fisa: FOI,
282747ad3c4Slazypassion errors: &mut VerifierErrors,
283220139b0Sedoardo marangoni ) -> VerifierStepResult {
284747ad3c4Slazypassion let _tt = timing::verifier();
285747ad3c4Slazypassion let verifier = Verifier::new(func, fisa.into());
286747ad3c4Slazypassion if cfg.is_valid() {
287747ad3c4Slazypassion verifier.cfg_integrity(cfg, errors)?;
288747ad3c4Slazypassion }
289747ad3c4Slazypassion if domtree.is_valid() {
290747ad3c4Slazypassion verifier.domtree_integrity(domtree, errors)?;
291747ad3c4Slazypassion }
292747ad3c4Slazypassion verifier.run(errors)
293747ad3c4Slazypassion }
294747ad3c4Slazypassion
29594ec88eaSChris Fallin #[derive(Clone, Copy, Debug)]
29694ec88eaSChris Fallin enum BlockCallTargetType {
29794ec88eaSChris Fallin Normal,
29894ec88eaSChris Fallin ExNormalRet,
29994ec88eaSChris Fallin Exception,
30094ec88eaSChris Fallin }
30194ec88eaSChris Fallin
302747ad3c4Slazypassion struct Verifier<'a> {
303747ad3c4Slazypassion func: &'a Function,
304747ad3c4Slazypassion expected_cfg: ControlFlowGraph,
305747ad3c4Slazypassion expected_domtree: DominatorTree,
306d7d48d5cSBenjamin Bouvier isa: Option<&'a dyn TargetIsa>,
307747ad3c4Slazypassion }
308747ad3c4Slazypassion
309747ad3c4Slazypassion impl<'a> Verifier<'a> {
new(func: &'a Function, fisa: FlagsOrIsa<'a>) -> Self310747ad3c4Slazypassion pub fn new(func: &'a Function, fisa: FlagsOrIsa<'a>) -> Self {
311747ad3c4Slazypassion let expected_cfg = ControlFlowGraph::with_function(func);
312747ad3c4Slazypassion let expected_domtree = DominatorTree::with_function(func, &expected_cfg);
313747ad3c4Slazypassion Self {
314747ad3c4Slazypassion func,
315747ad3c4Slazypassion expected_cfg,
316747ad3c4Slazypassion expected_domtree,
317747ad3c4Slazypassion isa: fisa.isa,
318747ad3c4Slazypassion }
319747ad3c4Slazypassion }
320747ad3c4Slazypassion
3213e5f0393SAndrew Brown /// Determine a contextual error string for an instruction.
322838f2f46SAndrew Brown #[inline]
context(&self, inst: Inst) -> String3233e5f0393SAndrew Brown fn context(&self, inst: Inst) -> String {
32443a86f14SBenjamin Bouvier self.func.dfg.display_inst(inst).to_string()
325838f2f46SAndrew Brown }
326838f2f46SAndrew Brown
327747ad3c4Slazypassion // Check for:
328747ad3c4Slazypassion // - cycles in the global value declarations.
329747ad3c4Slazypassion // - use of 'vmctx' when no special parameter declares it.
verify_global_values(&self, errors: &mut VerifierErrors) -> VerifierStepResult330220139b0Sedoardo marangoni fn verify_global_values(&self, errors: &mut VerifierErrors) -> VerifierStepResult {
331747ad3c4Slazypassion let mut cycle_seen = false;
332747ad3c4Slazypassion let mut seen = SparseSet::new();
333747ad3c4Slazypassion
334747ad3c4Slazypassion 'gvs: for gv in self.func.global_values.keys() {
335747ad3c4Slazypassion seen.clear();
336747ad3c4Slazypassion seen.insert(gv);
337747ad3c4Slazypassion
338747ad3c4Slazypassion let mut cur = gv;
339747ad3c4Slazypassion loop {
340747ad3c4Slazypassion match self.func.global_values[cur] {
341747ad3c4Slazypassion ir::GlobalValueData::Load { base, .. }
342747ad3c4Slazypassion | ir::GlobalValueData::IAddImm { base, .. } => {
343747ad3c4Slazypassion if seen.insert(base).is_some() {
344747ad3c4Slazypassion if !cycle_seen {
3453e5f0393SAndrew Brown errors.report((
346747ad3c4Slazypassion gv,
3473e5f0393SAndrew Brown format!("global value cycle: {}", DisplayList(seen.as_slice())),
3483e5f0393SAndrew Brown ));
349747ad3c4Slazypassion // ensures we don't report the cycle multiple times
350747ad3c4Slazypassion cycle_seen = true;
351747ad3c4Slazypassion }
352747ad3c4Slazypassion continue 'gvs;
353747ad3c4Slazypassion }
354747ad3c4Slazypassion
355747ad3c4Slazypassion cur = base;
356747ad3c4Slazypassion }
357747ad3c4Slazypassion _ => break,
358747ad3c4Slazypassion }
359747ad3c4Slazypassion }
360747ad3c4Slazypassion
361747ad3c4Slazypassion match self.func.global_values[gv] {
362747ad3c4Slazypassion ir::GlobalValueData::VMContext { .. } => {
363747ad3c4Slazypassion if self
364747ad3c4Slazypassion .func
365747ad3c4Slazypassion .special_param(ir::ArgumentPurpose::VMContext)
366747ad3c4Slazypassion .is_none()
367747ad3c4Slazypassion {
368a0442ea0SHamir Mahal errors.report((gv, format!("undeclared vmctx reference {gv}")));
369747ad3c4Slazypassion }
370747ad3c4Slazypassion }
371747ad3c4Slazypassion ir::GlobalValueData::IAddImm {
372747ad3c4Slazypassion base, global_type, ..
373747ad3c4Slazypassion } => {
374747ad3c4Slazypassion if !global_type.is_int() {
3753e5f0393SAndrew Brown errors.report((
376747ad3c4Slazypassion gv,
377a0442ea0SHamir Mahal format!("iadd_imm global value with non-int type {global_type}"),
3783e5f0393SAndrew Brown ));
379747ad3c4Slazypassion } else if let Some(isa) = self.isa {
380747ad3c4Slazypassion let base_type = self.func.global_values[base].global_type(isa);
381747ad3c4Slazypassion if global_type != base_type {
3823e5f0393SAndrew Brown errors.report((
383747ad3c4Slazypassion gv,
3843e5f0393SAndrew Brown format!(
385a0442ea0SHamir Mahal "iadd_imm type {global_type} differs from operand type {base_type}"
3863e5f0393SAndrew Brown ),
3873e5f0393SAndrew Brown ));
388747ad3c4Slazypassion }
389747ad3c4Slazypassion }
390747ad3c4Slazypassion }
391747ad3c4Slazypassion ir::GlobalValueData::Load { base, .. } => {
392747ad3c4Slazypassion if let Some(isa) = self.isa {
393747ad3c4Slazypassion let base_type = self.func.global_values[base].global_type(isa);
394747ad3c4Slazypassion let pointer_type = isa.pointer_type();
395747ad3c4Slazypassion if base_type != pointer_type {
3963e5f0393SAndrew Brown errors.report((
397747ad3c4Slazypassion gv,
3983e5f0393SAndrew Brown format!(
399a0442ea0SHamir Mahal "base {base} has type {base_type}, which is not the pointer type {pointer_type}"
4003e5f0393SAndrew Brown ),
4013e5f0393SAndrew Brown ));
402747ad3c4Slazypassion }
403747ad3c4Slazypassion }
404747ad3c4Slazypassion }
405747ad3c4Slazypassion _ => {}
406747ad3c4Slazypassion }
407747ad3c4Slazypassion }
408747ad3c4Slazypassion
409747ad3c4Slazypassion // Invalid global values shouldn't stop us from verifying the rest of the function
410747ad3c4Slazypassion Ok(())
411747ad3c4Slazypassion }
412747ad3c4Slazypassion
413832666c4SRyan Hunt /// Check that the given block can be encoded as a BB, by checking that only
414832666c4SRyan Hunt /// branching instructions are ending the block.
encodable_as_bb(&self, block: Block, errors: &mut VerifierErrors) -> VerifierStepResult415220139b0Sedoardo marangoni fn encodable_as_bb(&self, block: Block, errors: &mut VerifierErrors) -> VerifierStepResult {
416832666c4SRyan Hunt match self.func.is_block_basic(block) {
4178efaeec5SSean Stangl Ok(()) => Ok(()),
4183e5f0393SAndrew Brown Err((inst, message)) => errors.fatal((inst, self.context(inst), message)),
419460fdaa3SNicolas B. Pierron }
420460fdaa3SNicolas B. Pierron }
421460fdaa3SNicolas B. Pierron
block_integrity( &self, block: Block, inst: Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult422832666c4SRyan Hunt fn block_integrity(
423747ad3c4Slazypassion &self,
424832666c4SRyan Hunt block: Block,
425747ad3c4Slazypassion inst: Inst,
426747ad3c4Slazypassion errors: &mut VerifierErrors,
427220139b0Sedoardo marangoni ) -> VerifierStepResult {
42825bf8e0eSTrevor Elliott let is_terminator = self.func.dfg.insts[inst].opcode().is_terminator();
429832666c4SRyan Hunt let is_last_inst = self.func.layout.last_inst(block) == Some(inst);
430747ad3c4Slazypassion
431747ad3c4Slazypassion if is_terminator && !is_last_inst {
432747ad3c4Slazypassion // Terminating instructions only occur at the end of blocks.
4333e5f0393SAndrew Brown return errors.fatal((
434747ad3c4Slazypassion inst,
4353e5f0393SAndrew Brown self.context(inst),
436a0442ea0SHamir Mahal format!("a terminator instruction was encountered before the end of {block}"),
4373e5f0393SAndrew Brown ));
438747ad3c4Slazypassion }
439747ad3c4Slazypassion if is_last_inst && !is_terminator {
440832666c4SRyan Hunt return errors.fatal((block, "block does not end in a terminator instruction"));
441747ad3c4Slazypassion }
442747ad3c4Slazypassion
443832666c4SRyan Hunt // Instructions belong to the correct block.
444832666c4SRyan Hunt let inst_block = self.func.layout.inst_block(inst);
445832666c4SRyan Hunt if inst_block != Some(block) {
4463e5f0393SAndrew Brown return errors.fatal((
447838f2f46SAndrew Brown inst,
4483e5f0393SAndrew Brown self.context(inst),
449a0442ea0SHamir Mahal format!("should belong to {block} not {inst_block:?}"),
4503e5f0393SAndrew Brown ));
451747ad3c4Slazypassion }
452747ad3c4Slazypassion
453832666c4SRyan Hunt // Parameters belong to the correct block.
454832666c4SRyan Hunt for &arg in self.func.dfg.block_params(block) {
455747ad3c4Slazypassion match self.func.dfg.value_def(arg) {
456832666c4SRyan Hunt ValueDef::Param(arg_block, _) => {
457832666c4SRyan Hunt if block != arg_block {
458a0442ea0SHamir Mahal return errors.fatal((arg, format!("does not belong to {block}")));
459747ad3c4Slazypassion }
460747ad3c4Slazypassion }
461747ad3c4Slazypassion _ => {
4623e5f0393SAndrew Brown return errors.fatal((arg, "expected an argument, found a result"));
463747ad3c4Slazypassion }
464747ad3c4Slazypassion }
465747ad3c4Slazypassion }
466747ad3c4Slazypassion
467747ad3c4Slazypassion Ok(())
468747ad3c4Slazypassion }
469747ad3c4Slazypassion
instruction_integrity(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult470220139b0Sedoardo marangoni fn instruction_integrity(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult {
47125bf8e0eSTrevor Elliott let inst_data = &self.func.dfg.insts[inst];
472747ad3c4Slazypassion let dfg = &self.func.dfg;
473747ad3c4Slazypassion
474747ad3c4Slazypassion // The instruction format matches the opcode
475747ad3c4Slazypassion if inst_data.opcode().format() != InstructionFormat::from(inst_data) {
4763e5f0393SAndrew Brown return errors.fatal((
477747ad3c4Slazypassion inst,
4783e5f0393SAndrew Brown self.context(inst),
479838f2f46SAndrew Brown "instruction opcode doesn't match instruction format",
4803e5f0393SAndrew Brown ));
481747ad3c4Slazypassion }
482747ad3c4Slazypassion
483bdfb7465SNick Fitzgerald let expected_num_results = dfg.num_expected_results_for_verifier(inst);
484747ad3c4Slazypassion
485747ad3c4Slazypassion // All result values for multi-valued instructions are created
486747ad3c4Slazypassion let got_results = dfg.inst_results(inst).len();
487bdfb7465SNick Fitzgerald if got_results != expected_num_results {
4883e5f0393SAndrew Brown return errors.fatal((
489747ad3c4Slazypassion inst,
4903e5f0393SAndrew Brown self.context(inst),
491bdfb7465SNick Fitzgerald format!("expected {expected_num_results} result values, found {got_results}"),
4923e5f0393SAndrew Brown ));
493747ad3c4Slazypassion }
494747ad3c4Slazypassion
495747ad3c4Slazypassion self.verify_entity_references(inst, errors)
496747ad3c4Slazypassion }
497747ad3c4Slazypassion
verify_entity_references( &self, inst: Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult498747ad3c4Slazypassion fn verify_entity_references(
499747ad3c4Slazypassion &self,
500747ad3c4Slazypassion inst: Inst,
501747ad3c4Slazypassion errors: &mut VerifierErrors,
502220139b0Sedoardo marangoni ) -> VerifierStepResult {
503747ad3c4Slazypassion use crate::ir::instructions::InstructionData::*;
504747ad3c4Slazypassion
5051e6c13d8STrevor Elliott for arg in self.func.dfg.inst_values(inst) {
506747ad3c4Slazypassion self.verify_inst_arg(inst, arg, errors)?;
507747ad3c4Slazypassion
508747ad3c4Slazypassion // All used values must be attached to something.
509747ad3c4Slazypassion let original = self.func.dfg.resolve_aliases(arg);
510747ad3c4Slazypassion if !self.func.dfg.value_is_attached(original) {
5113e5f0393SAndrew Brown errors.report((
512747ad3c4Slazypassion inst,
5133e5f0393SAndrew Brown self.context(inst),
514a0442ea0SHamir Mahal format!("argument {arg} -> {original} is not attached"),
5153e5f0393SAndrew Brown ));
516747ad3c4Slazypassion }
517747ad3c4Slazypassion }
518747ad3c4Slazypassion
519747ad3c4Slazypassion for &res in self.func.dfg.inst_results(inst) {
520079ccf1fSBenjamin Bouvier self.verify_inst_result(inst, res, errors)?;
521747ad3c4Slazypassion }
522747ad3c4Slazypassion
52325bf8e0eSTrevor Elliott match self.func.dfg.insts[inst] {
524747ad3c4Slazypassion MultiAry { ref args, .. } => {
525747ad3c4Slazypassion self.verify_value_list(inst, args, errors)?;
526747ad3c4Slazypassion }
527a5698cedSTrevor Elliott Jump { destination, .. } => {
5281e6c13d8STrevor Elliott self.verify_block(inst, destination.block(&self.func.dfg.value_lists), errors)?;
529747ad3c4Slazypassion }
530b58a197dSTrevor Elliott Brif {
531b58a197dSTrevor Elliott arg,
532b58a197dSTrevor Elliott blocks: [block_then, block_else],
533b58a197dSTrevor Elliott ..
534b58a197dSTrevor Elliott } => {
535b58a197dSTrevor Elliott self.verify_value(inst, arg, errors)?;
536b58a197dSTrevor Elliott self.verify_block(inst, block_then.block(&self.func.dfg.value_lists), errors)?;
537b58a197dSTrevor Elliott self.verify_block(inst, block_else.block(&self.func.dfg.value_lists), errors)?;
538b58a197dSTrevor Elliott }
539d99783fcSTrevor Elliott BranchTable { table, .. } => {
540274415d5SBenjamin Bouvier self.verify_jump_table(inst, table, errors)?;
541274415d5SBenjamin Bouvier }
542747ad3c4Slazypassion Call {
543c00e9ea2SChris Fallin opcode,
544c00e9ea2SChris Fallin func_ref,
545c00e9ea2SChris Fallin ref args,
546c00e9ea2SChris Fallin ..
547747ad3c4Slazypassion } => {
548747ad3c4Slazypassion self.verify_func_ref(inst, func_ref, errors)?;
549747ad3c4Slazypassion self.verify_value_list(inst, args, errors)?;
55087ed3b60SChris Fallin self.verify_callee_patchability(inst, func_ref, opcode, errors)?;
551747ad3c4Slazypassion }
552747ad3c4Slazypassion CallIndirect {
553747ad3c4Slazypassion sig_ref, ref args, ..
554747ad3c4Slazypassion } => {
555747ad3c4Slazypassion self.verify_sig_ref(inst, sig_ref, errors)?;
556747ad3c4Slazypassion self.verify_value_list(inst, args, errors)?;
557747ad3c4Slazypassion }
55894ec88eaSChris Fallin TryCall {
55994ec88eaSChris Fallin func_ref,
56094ec88eaSChris Fallin ref args,
56194ec88eaSChris Fallin exception,
56294ec88eaSChris Fallin ..
56394ec88eaSChris Fallin } => {
56494ec88eaSChris Fallin self.verify_func_ref(inst, func_ref, errors)?;
56594ec88eaSChris Fallin self.verify_value_list(inst, args, errors)?;
56694ec88eaSChris Fallin self.verify_exception_table(inst, exception, errors)?;
56794ec88eaSChris Fallin self.verify_exception_compatible_abi(inst, exception, errors)?;
56894ec88eaSChris Fallin }
56994ec88eaSChris Fallin TryCallIndirect {
57094ec88eaSChris Fallin ref args,
57194ec88eaSChris Fallin exception,
57294ec88eaSChris Fallin ..
57394ec88eaSChris Fallin } => {
57494ec88eaSChris Fallin self.verify_value_list(inst, args, errors)?;
57594ec88eaSChris Fallin self.verify_exception_table(inst, exception, errors)?;
57694ec88eaSChris Fallin self.verify_exception_compatible_abi(inst, exception, errors)?;
57794ec88eaSChris Fallin }
578747ad3c4Slazypassion FuncAddr { func_ref, .. } => {
579747ad3c4Slazypassion self.verify_func_ref(inst, func_ref, errors)?;
580747ad3c4Slazypassion }
581747ad3c4Slazypassion StackLoad { stack_slot, .. } | StackStore { stack_slot, .. } => {
582747ad3c4Slazypassion self.verify_stack_slot(inst, stack_slot, errors)?;
583747ad3c4Slazypassion }
5849c43749dSSam Parker DynamicStackLoad {
5859c43749dSSam Parker dynamic_stack_slot, ..
5869c43749dSSam Parker }
5879c43749dSSam Parker | DynamicStackStore {
5889c43749dSSam Parker dynamic_stack_slot, ..
5899c43749dSSam Parker } => {
5909c43749dSSam Parker self.verify_dynamic_stack_slot(inst, dynamic_stack_slot, errors)?;
5919c43749dSSam Parker }
592747ad3c4Slazypassion UnaryGlobalValue { global_value, .. } => {
593747ad3c4Slazypassion self.verify_global_value(inst, global_value, errors)?;
594747ad3c4Slazypassion }
595660b8b28SBenjamin Bouvier NullAry {
596660b8b28SBenjamin Bouvier opcode: Opcode::GetPinnedReg,
597660b8b28SBenjamin Bouvier }
598660b8b28SBenjamin Bouvier | Unary {
599660b8b28SBenjamin Bouvier opcode: Opcode::SetPinnedReg,
600660b8b28SBenjamin Bouvier ..
601660b8b28SBenjamin Bouvier } => {
602660b8b28SBenjamin Bouvier if let Some(isa) = &self.isa {
603660b8b28SBenjamin Bouvier if !isa.flags().enable_pinned_reg() {
6043e5f0393SAndrew Brown return errors.fatal((
605660b8b28SBenjamin Bouvier inst,
6063e5f0393SAndrew Brown self.context(inst),
607838f2f46SAndrew Brown "GetPinnedReg/SetPinnedReg cannot be used without enable_pinned_reg",
6083e5f0393SAndrew Brown ));
609660b8b28SBenjamin Bouvier }
610660b8b28SBenjamin Bouvier } else {
6113e5f0393SAndrew Brown return errors.fatal((
6123e5f0393SAndrew Brown inst,
6133e5f0393SAndrew Brown self.context(inst),
6143e5f0393SAndrew Brown "GetPinnedReg/SetPinnedReg need an ISA!",
6153e5f0393SAndrew Brown ));
616660b8b28SBenjamin Bouvier }
617660b8b28SBenjamin Bouvier }
61842bba452SNick Fitzgerald NullAry {
61942bba452SNick Fitzgerald opcode: Opcode::GetFramePointer | Opcode::GetReturnAddress,
62042bba452SNick Fitzgerald } => {
62142bba452SNick Fitzgerald if let Some(isa) = &self.isa {
622dd07e354SAnton Kirilov // Backends may already rely on this check implicitly, so do
623dd07e354SAnton Kirilov // not relax it without verifying that it is safe to do so.
62442bba452SNick Fitzgerald if !isa.flags().preserve_frame_pointers() {
62542bba452SNick Fitzgerald return errors.fatal((
62642bba452SNick Fitzgerald inst,
62742bba452SNick Fitzgerald self.context(inst),
62842bba452SNick Fitzgerald "`get_frame_pointer`/`get_return_address` cannot be used without \
62942bba452SNick Fitzgerald enabling `preserve_frame_pointers`",
63042bba452SNick Fitzgerald ));
63142bba452SNick Fitzgerald }
63242bba452SNick Fitzgerald } else {
63342bba452SNick Fitzgerald return errors.fatal((
63442bba452SNick Fitzgerald inst,
63542bba452SNick Fitzgerald self.context(inst),
63642bba452SNick Fitzgerald "`get_frame_pointer`/`get_return_address` require an ISA!",
63742bba452SNick Fitzgerald ));
63842bba452SNick Fitzgerald }
63942bba452SNick Fitzgerald }
6403e5938e6SUlrich Weigand LoadNoOffset {
641863ac809SWander Lairson Costa opcode: Opcode::Bitcast,
6423e5938e6SUlrich Weigand flags,
643863ac809SWander Lairson Costa arg,
644863ac809SWander Lairson Costa } => {
6453e5938e6SUlrich Weigand self.verify_bitcast(inst, flags, arg, errors)?;
646863ac809SWander Lairson Costa }
6479afc64b4SIvor Wanders LoadNoOffset { opcode, arg, .. } if opcode.can_load() => {
6489afc64b4SIvor Wanders self.verify_is_address(inst, arg, errors)?;
6499afc64b4SIvor Wanders }
6509afc64b4SIvor Wanders Load { opcode, arg, .. } if opcode.can_load() => {
6519afc64b4SIvor Wanders self.verify_is_address(inst, arg, errors)?;
6529afc64b4SIvor Wanders }
6539afc64b4SIvor Wanders AtomicCas {
6549afc64b4SIvor Wanders opcode,
6559afc64b4SIvor Wanders args: [p, _, _],
6569afc64b4SIvor Wanders ..
6579afc64b4SIvor Wanders } if opcode.can_load() || opcode.can_store() => {
6589afc64b4SIvor Wanders self.verify_is_address(inst, p, errors)?;
6599afc64b4SIvor Wanders }
6609afc64b4SIvor Wanders AtomicRmw {
6619afc64b4SIvor Wanders opcode,
6629afc64b4SIvor Wanders args: [p, _],
6639afc64b4SIvor Wanders ..
6649afc64b4SIvor Wanders } if opcode.can_load() || opcode.can_store() => {
6659afc64b4SIvor Wanders self.verify_is_address(inst, p, errors)?;
6669afc64b4SIvor Wanders }
6679afc64b4SIvor Wanders Store {
6689afc64b4SIvor Wanders opcode,
6699afc64b4SIvor Wanders args: [_, p],
6709afc64b4SIvor Wanders ..
6719afc64b4SIvor Wanders } if opcode.can_store() => {
6729afc64b4SIvor Wanders self.verify_is_address(inst, p, errors)?;
6739afc64b4SIvor Wanders }
6749afc64b4SIvor Wanders StoreNoOffset {
6759afc64b4SIvor Wanders opcode,
6769afc64b4SIvor Wanders args: [_, p],
6779afc64b4SIvor Wanders ..
6789afc64b4SIvor Wanders } if opcode.can_store() => {
6799afc64b4SIvor Wanders self.verify_is_address(inst, p, errors)?;
6809afc64b4SIvor Wanders }
681fa35d888SAndrew Brown UnaryConst {
68241eca60bSbeetrees opcode: opcode @ (Opcode::Vconst | Opcode::F128const),
683fa35d888SAndrew Brown constant_handle,
684fa35d888SAndrew Brown ..
685fa35d888SAndrew Brown } => {
68641eca60bSbeetrees self.verify_constant_size(inst, opcode, constant_handle, errors)?;
687fa35d888SAndrew Brown }
688863ac809SWander Lairson Costa
6894c01ee2fSChris Fallin ExceptionHandlerAddress { block, imm, .. } => {
6904c01ee2fSChris Fallin self.verify_block(inst, block, errors)?;
6914c01ee2fSChris Fallin self.verify_try_call_handler_index(inst, block, imm.into(), errors)?;
6924c01ee2fSChris Fallin }
6934c01ee2fSChris Fallin
694747ad3c4Slazypassion // Exhaustive list so we can't forget to add new formats
69525e31739SJulian Seward AtomicCas { .. }
69625e31739SJulian Seward | AtomicRmw { .. }
69725e31739SJulian Seward | LoadNoOffset { .. }
69825e31739SJulian Seward | StoreNoOffset { .. }
69925e31739SJulian Seward | Unary { .. }
700fa35d888SAndrew Brown | UnaryConst { .. }
701747ad3c4Slazypassion | UnaryImm { .. }
70241eca60bSbeetrees | UnaryIeee16 { .. }
703747ad3c4Slazypassion | UnaryIeee32 { .. }
704747ad3c4Slazypassion | UnaryIeee64 { .. }
705747ad3c4Slazypassion | Binary { .. }
706a27a079dSAndrew Brown | BinaryImm8 { .. }
7070dd77d36SAndrew Brown | BinaryImm64 { .. }
708747ad3c4Slazypassion | Ternary { .. }
7097d6e94b9SAndrew Brown | TernaryImm8 { .. }
710af1499ceSAndrew Brown | Shuffle { .. }
71102620441STrevor Elliott | IntAddTrap { .. }
712747ad3c4Slazypassion | IntCompare { .. }
713747ad3c4Slazypassion | IntCompareImm { .. }
714747ad3c4Slazypassion | FloatCompare { .. }
715747ad3c4Slazypassion | Load { .. }
716747ad3c4Slazypassion | Store { .. }
717747ad3c4Slazypassion | Trap { .. }
718747ad3c4Slazypassion | CondTrap { .. }
719747ad3c4Slazypassion | NullAry { .. } => {}
720747ad3c4Slazypassion }
721747ad3c4Slazypassion
722747ad3c4Slazypassion Ok(())
723747ad3c4Slazypassion }
724747ad3c4Slazypassion
verify_block( &self, loc: impl Into<AnyEntity>, e: Block, errors: &mut VerifierErrors, ) -> VerifierStepResult725832666c4SRyan Hunt fn verify_block(
726747ad3c4Slazypassion &self,
727274415d5SBenjamin Bouvier loc: impl Into<AnyEntity>,
728832666c4SRyan Hunt e: Block,
729747ad3c4Slazypassion errors: &mut VerifierErrors,
730220139b0Sedoardo marangoni ) -> VerifierStepResult {
731832666c4SRyan Hunt if !self.func.dfg.block_is_valid(e) || !self.func.layout.is_block_inserted(e) {
732a0442ea0SHamir Mahal return errors.fatal((loc, format!("invalid block reference {e}")));
733747ad3c4Slazypassion }
734747ad3c4Slazypassion if let Some(entry_block) = self.func.layout.entry_block() {
735747ad3c4Slazypassion if e == entry_block {
736a0442ea0SHamir Mahal return errors.fatal((loc, format!("invalid reference to entry block {e}")));
737747ad3c4Slazypassion }
738747ad3c4Slazypassion }
739747ad3c4Slazypassion Ok(())
740747ad3c4Slazypassion }
741747ad3c4Slazypassion
verify_sig_ref( &self, inst: Inst, s: SigRef, errors: &mut VerifierErrors, ) -> VerifierStepResult742747ad3c4Slazypassion fn verify_sig_ref(
743747ad3c4Slazypassion &self,
744747ad3c4Slazypassion inst: Inst,
745747ad3c4Slazypassion s: SigRef,
746747ad3c4Slazypassion errors: &mut VerifierErrors,
747220139b0Sedoardo marangoni ) -> VerifierStepResult {
748747ad3c4Slazypassion if !self.func.dfg.signatures.is_valid(s) {
7493e5f0393SAndrew Brown errors.fatal((
7503e5f0393SAndrew Brown inst,
7513e5f0393SAndrew Brown self.context(inst),
752a0442ea0SHamir Mahal format!("invalid signature reference {s}"),
7533e5f0393SAndrew Brown ))
754747ad3c4Slazypassion } else {
755747ad3c4Slazypassion Ok(())
756747ad3c4Slazypassion }
757747ad3c4Slazypassion }
758747ad3c4Slazypassion
verify_func_ref( &self, inst: Inst, f: FuncRef, errors: &mut VerifierErrors, ) -> VerifierStepResult759747ad3c4Slazypassion fn verify_func_ref(
760747ad3c4Slazypassion &self,
761747ad3c4Slazypassion inst: Inst,
762747ad3c4Slazypassion f: FuncRef,
763747ad3c4Slazypassion errors: &mut VerifierErrors,
764220139b0Sedoardo marangoni ) -> VerifierStepResult {
765747ad3c4Slazypassion if !self.func.dfg.ext_funcs.is_valid(f) {
7663e5f0393SAndrew Brown errors.nonfatal((
7673e5f0393SAndrew Brown inst,
7683e5f0393SAndrew Brown self.context(inst),
769a0442ea0SHamir Mahal format!("invalid function reference {f}"),
7703e5f0393SAndrew Brown ))
771747ad3c4Slazypassion } else {
772747ad3c4Slazypassion Ok(())
773747ad3c4Slazypassion }
774747ad3c4Slazypassion }
775747ad3c4Slazypassion
verify_stack_slot( &self, inst: Inst, ss: StackSlot, errors: &mut VerifierErrors, ) -> VerifierStepResult776747ad3c4Slazypassion fn verify_stack_slot(
777747ad3c4Slazypassion &self,
778747ad3c4Slazypassion inst: Inst,
779747ad3c4Slazypassion ss: StackSlot,
780747ad3c4Slazypassion errors: &mut VerifierErrors,
781220139b0Sedoardo marangoni ) -> VerifierStepResult {
7829c43749dSSam Parker if !self.func.sized_stack_slots.is_valid(ss) {
783a0442ea0SHamir Mahal errors.nonfatal((inst, self.context(inst), format!("invalid stack slot {ss}")))
784747ad3c4Slazypassion } else {
785747ad3c4Slazypassion Ok(())
786747ad3c4Slazypassion }
787747ad3c4Slazypassion }
788747ad3c4Slazypassion
verify_dynamic_stack_slot( &self, inst: Inst, ss: DynamicStackSlot, errors: &mut VerifierErrors, ) -> VerifierStepResult7899c43749dSSam Parker fn verify_dynamic_stack_slot(
7909c43749dSSam Parker &self,
7919c43749dSSam Parker inst: Inst,
7929c43749dSSam Parker ss: DynamicStackSlot,
7939c43749dSSam Parker errors: &mut VerifierErrors,
794220139b0Sedoardo marangoni ) -> VerifierStepResult {
7959c43749dSSam Parker if !self.func.dynamic_stack_slots.is_valid(ss) {
7969c43749dSSam Parker errors.nonfatal((
7979c43749dSSam Parker inst,
7989c43749dSSam Parker self.context(inst),
799a0442ea0SHamir Mahal format!("invalid dynamic stack slot {ss}"),
8009c43749dSSam Parker ))
8019c43749dSSam Parker } else {
8029c43749dSSam Parker Ok(())
8039c43749dSSam Parker }
8049c43749dSSam Parker }
8059c43749dSSam Parker
verify_global_value( &self, inst: Inst, gv: GlobalValue, errors: &mut VerifierErrors, ) -> VerifierStepResult806747ad3c4Slazypassion fn verify_global_value(
807747ad3c4Slazypassion &self,
808747ad3c4Slazypassion inst: Inst,
809747ad3c4Slazypassion gv: GlobalValue,
810747ad3c4Slazypassion errors: &mut VerifierErrors,
811220139b0Sedoardo marangoni ) -> VerifierStepResult {
812747ad3c4Slazypassion if !self.func.global_values.is_valid(gv) {
8133e5f0393SAndrew Brown errors.nonfatal((
8143e5f0393SAndrew Brown inst,
8153e5f0393SAndrew Brown self.context(inst),
816a0442ea0SHamir Mahal format!("invalid global value {gv}"),
8173e5f0393SAndrew Brown ))
818747ad3c4Slazypassion } else {
819747ad3c4Slazypassion Ok(())
820747ad3c4Slazypassion }
821747ad3c4Slazypassion }
822747ad3c4Slazypassion
verify_value_list( &self, inst: Inst, l: &ValueList, errors: &mut VerifierErrors, ) -> VerifierStepResult823747ad3c4Slazypassion fn verify_value_list(
824747ad3c4Slazypassion &self,
825747ad3c4Slazypassion inst: Inst,
826747ad3c4Slazypassion l: &ValueList,
827747ad3c4Slazypassion errors: &mut VerifierErrors,
828220139b0Sedoardo marangoni ) -> VerifierStepResult {
829747ad3c4Slazypassion if !l.is_valid(&self.func.dfg.value_lists) {
8303e5f0393SAndrew Brown errors.nonfatal((
831838f2f46SAndrew Brown inst,
8323e5f0393SAndrew Brown self.context(inst),
833a0442ea0SHamir Mahal format!("invalid value list reference {l:?}"),
8343e5f0393SAndrew Brown ))
835747ad3c4Slazypassion } else {
836747ad3c4Slazypassion Ok(())
837747ad3c4Slazypassion }
838747ad3c4Slazypassion }
839747ad3c4Slazypassion
verify_jump_table( &self, inst: Inst, j: JumpTable, errors: &mut VerifierErrors, ) -> VerifierStepResult840747ad3c4Slazypassion fn verify_jump_table(
841747ad3c4Slazypassion &self,
842747ad3c4Slazypassion inst: Inst,
843747ad3c4Slazypassion j: JumpTable,
844747ad3c4Slazypassion errors: &mut VerifierErrors,
845220139b0Sedoardo marangoni ) -> VerifierStepResult {
846b0b3f67cSTrevor Elliott if !self.func.stencil.dfg.jump_tables.is_valid(j) {
8473e5f0393SAndrew Brown errors.nonfatal((
8483e5f0393SAndrew Brown inst,
8493e5f0393SAndrew Brown self.context(inst),
850a0442ea0SHamir Mahal format!("invalid jump table reference {j}"),
8513e5f0393SAndrew Brown ))
852747ad3c4Slazypassion } else {
85380c147d9STrevor Elliott let pool = &self.func.stencil.dfg.value_lists;
85480c147d9STrevor Elliott for block in self.func.stencil.dfg.jump_tables[j].all_branches() {
85580c147d9STrevor Elliott self.verify_block(inst, block.block(pool), errors)?;
85615fe9c7cSTrevor Elliott }
857747ad3c4Slazypassion Ok(())
858747ad3c4Slazypassion }
859747ad3c4Slazypassion }
860747ad3c4Slazypassion
verify_exception_table( &self, inst: Inst, et: ExceptionTable, errors: &mut VerifierErrors, ) -> VerifierStepResult86194ec88eaSChris Fallin fn verify_exception_table(
86294ec88eaSChris Fallin &self,
86394ec88eaSChris Fallin inst: Inst,
86494ec88eaSChris Fallin et: ExceptionTable,
86594ec88eaSChris Fallin errors: &mut VerifierErrors,
86694ec88eaSChris Fallin ) -> VerifierStepResult {
86794ec88eaSChris Fallin // Verify that the exception table reference itself is valid.
86894ec88eaSChris Fallin if !self.func.stencil.dfg.exception_tables.is_valid(et) {
86994ec88eaSChris Fallin errors.nonfatal((
87094ec88eaSChris Fallin inst,
87194ec88eaSChris Fallin self.context(inst),
87294ec88eaSChris Fallin format!("invalid exception table reference {et}"),
87394ec88eaSChris Fallin ))?;
87494ec88eaSChris Fallin }
87594ec88eaSChris Fallin
87694ec88eaSChris Fallin let pool = &self.func.stencil.dfg.value_lists;
87794ec88eaSChris Fallin let exdata = &self.func.stencil.dfg.exception_tables[et];
87894ec88eaSChris Fallin
87994ec88eaSChris Fallin // Verify that the exception table's signature reference
88094ec88eaSChris Fallin // is valid.
88194ec88eaSChris Fallin self.verify_sig_ref(inst, exdata.signature(), errors)?;
88294ec88eaSChris Fallin
88394ec88eaSChris Fallin // Verify that the exception table's block references are valid.
88494ec88eaSChris Fallin for block in exdata.all_branches() {
88594ec88eaSChris Fallin self.verify_block(inst, block.block(pool), errors)?;
88694ec88eaSChris Fallin }
88794ec88eaSChris Fallin Ok(())
88894ec88eaSChris Fallin }
88994ec88eaSChris Fallin
verify_exception_compatible_abi( &self, inst: Inst, et: ExceptionTable, errors: &mut VerifierErrors, ) -> VerifierStepResult89094ec88eaSChris Fallin fn verify_exception_compatible_abi(
89194ec88eaSChris Fallin &self,
89294ec88eaSChris Fallin inst: Inst,
89394ec88eaSChris Fallin et: ExceptionTable,
89494ec88eaSChris Fallin errors: &mut VerifierErrors,
89594ec88eaSChris Fallin ) -> VerifierStepResult {
89694ec88eaSChris Fallin let callee_sig_ref = self.func.dfg.exception_tables[et].signature();
89794ec88eaSChris Fallin let callee_sig = &self.func.dfg.signatures[callee_sig_ref];
89894ec88eaSChris Fallin let callee_call_conv = callee_sig.call_conv;
89994ec88eaSChris Fallin if !callee_call_conv.supports_exceptions() {
90094ec88eaSChris Fallin errors.nonfatal((
90194ec88eaSChris Fallin inst,
90294ec88eaSChris Fallin self.context(inst),
90394ec88eaSChris Fallin format!(
90494ec88eaSChris Fallin "calling convention `{callee_call_conv}` of callee does not support exceptions"
90594ec88eaSChris Fallin ),
90694ec88eaSChris Fallin ))?;
90794ec88eaSChris Fallin }
90894ec88eaSChris Fallin Ok(())
90994ec88eaSChris Fallin }
91094ec88eaSChris Fallin
verify_callee_patchability( &self, inst: Inst, func_ref: FuncRef, opcode: Opcode, errors: &mut VerifierErrors, ) -> VerifierStepResult91187ed3b60SChris Fallin fn verify_callee_patchability(
912c00e9ea2SChris Fallin &self,
913c00e9ea2SChris Fallin inst: Inst,
914c00e9ea2SChris Fallin func_ref: FuncRef,
915c00e9ea2SChris Fallin opcode: Opcode,
916c00e9ea2SChris Fallin errors: &mut VerifierErrors,
917c00e9ea2SChris Fallin ) -> VerifierStepResult {
91887ed3b60SChris Fallin let ir::ExtFuncData {
91987ed3b60SChris Fallin patchable,
92087ed3b60SChris Fallin colocated,
92187ed3b60SChris Fallin signature,
92287ed3b60SChris Fallin name: _,
92387ed3b60SChris Fallin } = self.func.dfg.ext_funcs[func_ref];
92487ed3b60SChris Fallin let signature = &self.func.dfg.signatures[signature];
92587ed3b60SChris Fallin if patchable && (opcode == Opcode::ReturnCall || opcode == Opcode::ReturnCallIndirect) {
92687ed3b60SChris Fallin errors.fatal((
92787ed3b60SChris Fallin inst,
92887ed3b60SChris Fallin self.context(inst),
92987ed3b60SChris Fallin "patchable funcref cannot be used in a return_call".to_string(),
93087ed3b60SChris Fallin ))?;
93187ed3b60SChris Fallin }
93287ed3b60SChris Fallin if patchable && !colocated {
933c00e9ea2SChris Fallin errors.fatal((
934c00e9ea2SChris Fallin inst,
935c00e9ea2SChris Fallin self.context(inst),
936c00e9ea2SChris Fallin "patchable call to non-colocated function".to_string(),
937c00e9ea2SChris Fallin ))?;
938c00e9ea2SChris Fallin }
93987ed3b60SChris Fallin if patchable && !signature.returns.is_empty() {
940c00e9ea2SChris Fallin errors.fatal((
941c00e9ea2SChris Fallin inst,
942c00e9ea2SChris Fallin self.context(inst),
94387ed3b60SChris Fallin "patchable call cannot occur to a function with return values".to_string(),
944c00e9ea2SChris Fallin ))?;
945c00e9ea2SChris Fallin }
946c00e9ea2SChris Fallin Ok(())
947c00e9ea2SChris Fallin }
948c00e9ea2SChris Fallin
verify_value( &self, loc_inst: Inst, v: Value, errors: &mut VerifierErrors, ) -> VerifierStepResult949747ad3c4Slazypassion fn verify_value(
950747ad3c4Slazypassion &self,
951747ad3c4Slazypassion loc_inst: Inst,
952747ad3c4Slazypassion v: Value,
953747ad3c4Slazypassion errors: &mut VerifierErrors,
954220139b0Sedoardo marangoni ) -> VerifierStepResult {
955747ad3c4Slazypassion let dfg = &self.func.dfg;
956747ad3c4Slazypassion if !dfg.value_is_valid(v) {
9573e5f0393SAndrew Brown errors.nonfatal((
9583e5f0393SAndrew Brown loc_inst,
9593e5f0393SAndrew Brown self.context(loc_inst),
960a0442ea0SHamir Mahal format!("invalid value reference {v}"),
9613e5f0393SAndrew Brown ))
962747ad3c4Slazypassion } else {
963747ad3c4Slazypassion Ok(())
964747ad3c4Slazypassion }
965747ad3c4Slazypassion }
966747ad3c4Slazypassion
verify_inst_arg( &self, loc_inst: Inst, v: Value, errors: &mut VerifierErrors, ) -> VerifierStepResult967747ad3c4Slazypassion fn verify_inst_arg(
968747ad3c4Slazypassion &self,
969747ad3c4Slazypassion loc_inst: Inst,
970747ad3c4Slazypassion v: Value,
971747ad3c4Slazypassion errors: &mut VerifierErrors,
972220139b0Sedoardo marangoni ) -> VerifierStepResult {
973747ad3c4Slazypassion self.verify_value(loc_inst, v, errors)?;
974747ad3c4Slazypassion
975747ad3c4Slazypassion let dfg = &self.func.dfg;
976a81c2068Sbjorn3 let loc_block = self
977a81c2068Sbjorn3 .func
978a81c2068Sbjorn3 .layout
979a81c2068Sbjorn3 .inst_block(loc_inst)
980a81c2068Sbjorn3 .expect("Instruction not in layout.");
981832666c4SRyan Hunt let is_reachable = self.expected_domtree.is_reachable(loc_block);
982747ad3c4Slazypassion
983747ad3c4Slazypassion // SSA form
984747ad3c4Slazypassion match dfg.value_def(v) {
985747ad3c4Slazypassion ValueDef::Result(def_inst, _) => {
986747ad3c4Slazypassion // Value is defined by an instruction that exists.
987747ad3c4Slazypassion if !dfg.inst_is_valid(def_inst) {
9883e5f0393SAndrew Brown return errors.fatal((
989747ad3c4Slazypassion loc_inst,
9903e5f0393SAndrew Brown self.context(loc_inst),
991a0442ea0SHamir Mahal format!("{v} is defined by invalid instruction {def_inst}"),
9923e5f0393SAndrew Brown ));
993747ad3c4Slazypassion }
99407f335dcSRyan Hunt // Defining instruction is inserted in a block.
995832666c4SRyan Hunt if self.func.layout.inst_block(def_inst) == None {
9963e5f0393SAndrew Brown return errors.fatal((
997747ad3c4Slazypassion loc_inst,
9983e5f0393SAndrew Brown self.context(loc_inst),
999a0442ea0SHamir Mahal format!("{v} is defined by {def_inst} which has no block"),
10003e5f0393SAndrew Brown ));
1001747ad3c4Slazypassion }
1002747ad3c4Slazypassion // Defining instruction dominates the instruction that uses the value.
1003747ad3c4Slazypassion if is_reachable {
10043a14fa39SPaul Nodet if !self
10053a14fa39SPaul Nodet .expected_domtree
10063a14fa39SPaul Nodet .dominates(def_inst, loc_inst, &self.func.layout)
10073a14fa39SPaul Nodet {
10083e5f0393SAndrew Brown return errors.fatal((
1009747ad3c4Slazypassion loc_inst,
10103e5f0393SAndrew Brown self.context(loc_inst),
1011a0442ea0SHamir Mahal format!("uses value {v} from non-dominating {def_inst}"),
10123e5f0393SAndrew Brown ));
1013747ad3c4Slazypassion }
1014747ad3c4Slazypassion if def_inst == loc_inst {
10153e5f0393SAndrew Brown return errors.fatal((
1016838f2f46SAndrew Brown loc_inst,
10173e5f0393SAndrew Brown self.context(loc_inst),
1018a0442ea0SHamir Mahal format!("uses value {v} from itself"),
10193e5f0393SAndrew Brown ));
1020747ad3c4Slazypassion }
1021747ad3c4Slazypassion }
1022747ad3c4Slazypassion }
1023832666c4SRyan Hunt ValueDef::Param(block, _) => {
1024832666c4SRyan Hunt // Value is defined by an existing block.
1025832666c4SRyan Hunt if !dfg.block_is_valid(block) {
10263e5f0393SAndrew Brown return errors.fatal((
1027838f2f46SAndrew Brown loc_inst,
10283e5f0393SAndrew Brown self.context(loc_inst),
1029a0442ea0SHamir Mahal format!("{v} is defined by invalid block {block}"),
10303e5f0393SAndrew Brown ));
1031747ad3c4Slazypassion }
1032832666c4SRyan Hunt // Defining block is inserted in the layout
1033832666c4SRyan Hunt if !self.func.layout.is_block_inserted(block) {
10343e5f0393SAndrew Brown return errors.fatal((
1035747ad3c4Slazypassion loc_inst,
10363e5f0393SAndrew Brown self.context(loc_inst),
1037a0442ea0SHamir Mahal format!("{v} is defined by {block} which is not in the layout"),
10383e5f0393SAndrew Brown ));
1039747ad3c4Slazypassion }
1040e33e0f21SKaran Lokchandani let user_block = self.func.layout.inst_block(loc_inst).expect("Expected instruction to be in a block as we're traversing code already in layout");
1041832666c4SRyan Hunt // The defining block dominates the instruction using this value.
10423a14fa39SPaul Nodet if is_reachable && !self.expected_domtree.block_dominates(block, user_block) {
10433e5f0393SAndrew Brown return errors.fatal((
1044747ad3c4Slazypassion loc_inst,
10453e5f0393SAndrew Brown self.context(loc_inst),
1046a0442ea0SHamir Mahal format!("uses value arg from non-dominating {block}"),
10473e5f0393SAndrew Brown ));
1048747ad3c4Slazypassion }
1049747ad3c4Slazypassion }
1050f980defeSChris Fallin ValueDef::Union(_, _) => {
1051f980defeSChris Fallin // Nothing: union nodes themselves have no location,
1052f980defeSChris Fallin // so we cannot check any dominance properties.
1053f980defeSChris Fallin }
1054747ad3c4Slazypassion }
1055747ad3c4Slazypassion Ok(())
1056747ad3c4Slazypassion }
1057747ad3c4Slazypassion
verify_inst_result( &self, loc_inst: Inst, v: Value, errors: &mut VerifierErrors, ) -> VerifierStepResult1058747ad3c4Slazypassion fn verify_inst_result(
1059747ad3c4Slazypassion &self,
1060747ad3c4Slazypassion loc_inst: Inst,
1061747ad3c4Slazypassion v: Value,
1062747ad3c4Slazypassion errors: &mut VerifierErrors,
1063220139b0Sedoardo marangoni ) -> VerifierStepResult {
1064747ad3c4Slazypassion self.verify_value(loc_inst, v, errors)?;
1065747ad3c4Slazypassion
1066747ad3c4Slazypassion match self.func.dfg.value_def(v) {
1067747ad3c4Slazypassion ValueDef::Result(def_inst, _) => {
1068747ad3c4Slazypassion if def_inst != loc_inst {
10693e5f0393SAndrew Brown errors.fatal((
1070747ad3c4Slazypassion loc_inst,
10713e5f0393SAndrew Brown self.context(loc_inst),
1072a0442ea0SHamir Mahal format!("instruction result {v} is not defined by the instruction"),
10733e5f0393SAndrew Brown ))
1074747ad3c4Slazypassion } else {
1075747ad3c4Slazypassion Ok(())
1076747ad3c4Slazypassion }
1077747ad3c4Slazypassion }
10783e5f0393SAndrew Brown ValueDef::Param(_, _) => errors.fatal((
1079747ad3c4Slazypassion loc_inst,
10803e5f0393SAndrew Brown self.context(loc_inst),
1081a0442ea0SHamir Mahal format!("instruction result {v} is not defined by the instruction"),
10823e5f0393SAndrew Brown )),
1083f980defeSChris Fallin ValueDef::Union(_, _) => errors.fatal((
1084f980defeSChris Fallin loc_inst,
1085f980defeSChris Fallin self.context(loc_inst),
1086a0442ea0SHamir Mahal format!("instruction result {v} is a union node"),
1087f980defeSChris Fallin )),
1088747ad3c4Slazypassion }
1089747ad3c4Slazypassion }
1090747ad3c4Slazypassion
verify_bitcast( &self, inst: Inst, flags: MemFlags, arg: Value, errors: &mut VerifierErrors, ) -> VerifierStepResult1091863ac809SWander Lairson Costa fn verify_bitcast(
1092863ac809SWander Lairson Costa &self,
1093863ac809SWander Lairson Costa inst: Inst,
10943e5938e6SUlrich Weigand flags: MemFlags,
1095863ac809SWander Lairson Costa arg: Value,
1096863ac809SWander Lairson Costa errors: &mut VerifierErrors,
1097220139b0Sedoardo marangoni ) -> VerifierStepResult {
1098863ac809SWander Lairson Costa let typ = self.func.dfg.ctrl_typevar(inst);
1099863ac809SWander Lairson Costa let value_type = self.func.dfg.value_type(arg);
1100863ac809SWander Lairson Costa
1101961107ecSUlrich Weigand if typ.bits() != value_type.bits() {
1102e786bda0SDamian Heaton errors.fatal((
1103e786bda0SDamian Heaton inst,
1104e786bda0SDamian Heaton format!(
1105e786bda0SDamian Heaton "The bitcast argument {} has a type of {} bits, which doesn't match an expected type of {} bits",
1106e786bda0SDamian Heaton arg,
1107e786bda0SDamian Heaton value_type.bits(),
1108e786bda0SDamian Heaton typ.bits()
1109e786bda0SDamian Heaton ),
1110e786bda0SDamian Heaton ))
11113e5938e6SUlrich Weigand } else if flags != MemFlags::new()
11123e5938e6SUlrich Weigand && flags != MemFlags::new().with_endianness(ir::Endianness::Little)
11133e5938e6SUlrich Weigand && flags != MemFlags::new().with_endianness(ir::Endianness::Big)
11143e5938e6SUlrich Weigand {
11153e5938e6SUlrich Weigand errors.fatal((
11163e5938e6SUlrich Weigand inst,
11173e5938e6SUlrich Weigand "The bitcast instruction only accepts the `big` or `little` memory flags",
11183e5938e6SUlrich Weigand ))
11193e5938e6SUlrich Weigand } else if flags == MemFlags::new() && typ.lane_count() != value_type.lane_count() {
11203e5938e6SUlrich Weigand errors.fatal((
11213e5938e6SUlrich Weigand inst,
11223e5938e6SUlrich Weigand "Byte order specifier required for bitcast instruction changing lane count",
11233e5938e6SUlrich Weigand ))
1124863ac809SWander Lairson Costa } else {
1125863ac809SWander Lairson Costa Ok(())
1126863ac809SWander Lairson Costa }
1127863ac809SWander Lairson Costa }
1128863ac809SWander Lairson Costa
verify_constant_size( &self, inst: Inst, opcode: Opcode, constant: Constant, errors: &mut VerifierErrors, ) -> VerifierStepResult1129fa35d888SAndrew Brown fn verify_constant_size(
1130fa35d888SAndrew Brown &self,
1131fa35d888SAndrew Brown inst: Inst,
113241eca60bSbeetrees opcode: Opcode,
1133fa35d888SAndrew Brown constant: Constant,
1134fa35d888SAndrew Brown errors: &mut VerifierErrors,
1135220139b0Sedoardo marangoni ) -> VerifierStepResult {
113641eca60bSbeetrees let type_size = match opcode {
113741eca60bSbeetrees Opcode::F128const => types::F128.bytes(),
113841eca60bSbeetrees Opcode::Vconst => self.func.dfg.ctrl_typevar(inst).bytes(),
113941eca60bSbeetrees _ => unreachable!("unexpected opcode {opcode:?}"),
114041eca60bSbeetrees } as usize;
1141fa35d888SAndrew Brown let constant_size = self.func.dfg.constants.get(constant).len();
1142fa35d888SAndrew Brown if type_size != constant_size {
1143fa35d888SAndrew Brown errors.fatal((
1144fa35d888SAndrew Brown inst,
1145fa35d888SAndrew Brown format!(
1146a0442ea0SHamir Mahal "The instruction expects {constant} to have a size of {type_size} bytes but it has {constant_size}"
1147fa35d888SAndrew Brown ),
1148fa35d888SAndrew Brown ))
1149fa35d888SAndrew Brown } else {
1150fa35d888SAndrew Brown Ok(())
1151fa35d888SAndrew Brown }
1152fa35d888SAndrew Brown }
1153fa35d888SAndrew Brown
verify_is_address( &self, loc_inst: Inst, v: Value, errors: &mut VerifierErrors, ) -> VerifierStepResult11549afc64b4SIvor Wanders fn verify_is_address(
11559afc64b4SIvor Wanders &self,
11569afc64b4SIvor Wanders loc_inst: Inst,
11579afc64b4SIvor Wanders v: Value,
11589afc64b4SIvor Wanders errors: &mut VerifierErrors,
11599afc64b4SIvor Wanders ) -> VerifierStepResult {
11609afc64b4SIvor Wanders if let Some(isa) = self.isa {
11619afc64b4SIvor Wanders let pointer_width = isa.triple().pointer_width()?;
11629afc64b4SIvor Wanders let value_type = self.func.dfg.value_type(v);
11639afc64b4SIvor Wanders let expected_width = pointer_width.bits() as u32;
11649afc64b4SIvor Wanders let value_width = value_type.bits();
11659afc64b4SIvor Wanders if expected_width != value_width {
11669afc64b4SIvor Wanders errors.nonfatal((
11679afc64b4SIvor Wanders loc_inst,
11689afc64b4SIvor Wanders self.context(loc_inst),
11699afc64b4SIvor Wanders format!("invalid pointer width (got {value_width}, expected {expected_width}) encountered {v}"),
11709afc64b4SIvor Wanders ))
11719afc64b4SIvor Wanders } else {
11729afc64b4SIvor Wanders Ok(())
11739afc64b4SIvor Wanders }
11749afc64b4SIvor Wanders } else {
11759afc64b4SIvor Wanders Ok(())
11769afc64b4SIvor Wanders }
11779afc64b4SIvor Wanders }
11789afc64b4SIvor Wanders
domtree_integrity( &self, domtree: &DominatorTree, errors: &mut VerifierErrors, ) -> VerifierStepResult1179747ad3c4Slazypassion fn domtree_integrity(
1180747ad3c4Slazypassion &self,
1181747ad3c4Slazypassion domtree: &DominatorTree,
1182747ad3c4Slazypassion errors: &mut VerifierErrors,
1183220139b0Sedoardo marangoni ) -> VerifierStepResult {
1184747ad3c4Slazypassion // We consider two `DominatorTree`s to be equal if they return the same immediate
1185832666c4SRyan Hunt // dominator for each block. Therefore the current domtree is valid if it matches the freshly
1186747ad3c4Slazypassion // computed one.
1187832666c4SRyan Hunt for block in self.func.layout.blocks() {
1188832666c4SRyan Hunt let expected = self.expected_domtree.idom(block);
1189832666c4SRyan Hunt let got = domtree.idom(block);
1190747ad3c4Slazypassion if got != expected {
11913e5f0393SAndrew Brown return errors.fatal((
1192832666c4SRyan Hunt block,
1193a0442ea0SHamir Mahal format!("invalid domtree, expected idom({block}) = {expected:?}, got {got:?}"),
11943e5f0393SAndrew Brown ));
1195747ad3c4Slazypassion }
1196747ad3c4Slazypassion }
1197747ad3c4Slazypassion // We also verify if the postorder defined by `DominatorTree` is sane
1198747ad3c4Slazypassion if domtree.cfg_postorder().len() != self.expected_domtree.cfg_postorder().len() {
11993e5f0393SAndrew Brown return errors.fatal((
1200747ad3c4Slazypassion AnyEntity::Function,
1201832666c4SRyan Hunt "incorrect number of Blocks in postorder traversal",
12023e5f0393SAndrew Brown ));
1203747ad3c4Slazypassion }
1204832666c4SRyan Hunt for (index, (&test_block, &true_block)) in domtree
1205747ad3c4Slazypassion .cfg_postorder()
1206747ad3c4Slazypassion .iter()
1207747ad3c4Slazypassion .zip(self.expected_domtree.cfg_postorder().iter())
1208747ad3c4Slazypassion .enumerate()
1209747ad3c4Slazypassion {
1210832666c4SRyan Hunt if test_block != true_block {
12113e5f0393SAndrew Brown return errors.fatal((
1212832666c4SRyan Hunt test_block,
12133e5f0393SAndrew Brown format!(
1214a0442ea0SHamir Mahal "invalid domtree, postorder block number {index} should be {true_block}, got {test_block}"
12153e5f0393SAndrew Brown ),
12163e5f0393SAndrew Brown ));
1217747ad3c4Slazypassion }
1218747ad3c4Slazypassion }
1219747ad3c4Slazypassion Ok(())
1220747ad3c4Slazypassion }
1221747ad3c4Slazypassion
typecheck_entry_block_params(&self, errors: &mut VerifierErrors) -> VerifierStepResult1222220139b0Sedoardo marangoni fn typecheck_entry_block_params(&self, errors: &mut VerifierErrors) -> VerifierStepResult {
1223832666c4SRyan Hunt if let Some(block) = self.func.layout.entry_block() {
1224747ad3c4Slazypassion let expected_types = &self.func.signature.params;
1225832666c4SRyan Hunt let block_param_count = self.func.dfg.num_block_params(block);
1226747ad3c4Slazypassion
1227832666c4SRyan Hunt if block_param_count != expected_types.len() {
12283e5f0393SAndrew Brown return errors.fatal((
1229832666c4SRyan Hunt block,
12303e5f0393SAndrew Brown format!(
1231747ad3c4Slazypassion "entry block parameters ({}) must match function signature ({})",
1232832666c4SRyan Hunt block_param_count,
1233747ad3c4Slazypassion expected_types.len()
12343e5f0393SAndrew Brown ),
12353e5f0393SAndrew Brown ));
1236747ad3c4Slazypassion }
1237747ad3c4Slazypassion
1238832666c4SRyan Hunt for (i, &arg) in self.func.dfg.block_params(block).iter().enumerate() {
1239747ad3c4Slazypassion let arg_type = self.func.dfg.value_type(arg);
1240747ad3c4Slazypassion if arg_type != expected_types[i].value_type {
12413e5f0393SAndrew Brown errors.report((
1242832666c4SRyan Hunt block,
12433e5f0393SAndrew Brown format!(
1244747ad3c4Slazypassion "entry block parameter {} expected to have type {}, got {}",
12453e5f0393SAndrew Brown i, expected_types[i], arg_type
12463e5f0393SAndrew Brown ),
12473e5f0393SAndrew Brown ));
1248747ad3c4Slazypassion }
1249747ad3c4Slazypassion }
1250747ad3c4Slazypassion }
1251747ad3c4Slazypassion
1252747ad3c4Slazypassion errors.as_result()
1253747ad3c4Slazypassion }
1254747ad3c4Slazypassion
check_entry_not_cold(&self, errors: &mut VerifierErrors) -> VerifierStepResult1255220139b0Sedoardo marangoni fn check_entry_not_cold(&self, errors: &mut VerifierErrors) -> VerifierStepResult {
1256953f83e6SChris Fallin if let Some(entry_block) = self.func.layout.entry_block() {
1257953f83e6SChris Fallin if self.func.layout.is_cold(entry_block) {
1258953f83e6SChris Fallin return errors
1259953f83e6SChris Fallin .fatal((entry_block, format!("entry block cannot be marked as cold")));
1260953f83e6SChris Fallin }
1261953f83e6SChris Fallin }
1262953f83e6SChris Fallin errors.as_result()
1263953f83e6SChris Fallin }
1264953f83e6SChris Fallin
typecheck(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult1265220139b0Sedoardo marangoni fn typecheck(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult {
126625bf8e0eSTrevor Elliott let inst_data = &self.func.dfg.insts[inst];
1267747ad3c4Slazypassion let constraints = inst_data.opcode().constraints();
1268747ad3c4Slazypassion
1269747ad3c4Slazypassion let ctrl_type = if let Some(value_typeset) = constraints.ctrl_typeset() {
1270747ad3c4Slazypassion // For polymorphic opcodes, determine the controlling type variable first.
1271747ad3c4Slazypassion let ctrl_type = self.func.dfg.ctrl_typevar(inst);
1272747ad3c4Slazypassion
1273747ad3c4Slazypassion if !value_typeset.contains(ctrl_type) {
12743e5f0393SAndrew Brown errors.report((
1275747ad3c4Slazypassion inst,
12763e5f0393SAndrew Brown self.context(inst),
127792024ad1SLuna P-C format!(
1278a0442ea0SHamir Mahal "has an invalid controlling type {ctrl_type} (allowed set is {value_typeset:?})"
127992024ad1SLuna P-C ),
12803e5f0393SAndrew Brown ));
1281747ad3c4Slazypassion }
1282747ad3c4Slazypassion
1283747ad3c4Slazypassion ctrl_type
1284747ad3c4Slazypassion } else {
1285747ad3c4Slazypassion // Non-polymorphic instructions don't check the controlling type variable, so `Option`
1286747ad3c4Slazypassion // is unnecessary and we can just make it `INVALID`.
1287747ad3c4Slazypassion types::INVALID
1288747ad3c4Slazypassion };
1289747ad3c4Slazypassion
1290747ad3c4Slazypassion // Typechecking instructions is never fatal
1291079ccf1fSBenjamin Bouvier let _ = self.typecheck_results(inst, ctrl_type, errors);
1292079ccf1fSBenjamin Bouvier let _ = self.typecheck_fixed_args(inst, ctrl_type, errors);
1293079ccf1fSBenjamin Bouvier let _ = self.typecheck_variable_args(inst, errors);
1294079ccf1fSBenjamin Bouvier let _ = self.typecheck_return(inst, errors);
1295f5ad74e5STrevor Elliott let _ = self.typecheck_special(inst, errors);
1296747ad3c4Slazypassion
1297747ad3c4Slazypassion Ok(())
1298747ad3c4Slazypassion }
1299747ad3c4Slazypassion
typecheck_results( &self, inst: Inst, ctrl_type: Type, errors: &mut VerifierErrors, ) -> VerifierStepResult1300747ad3c4Slazypassion fn typecheck_results(
1301747ad3c4Slazypassion &self,
1302747ad3c4Slazypassion inst: Inst,
1303747ad3c4Slazypassion ctrl_type: Type,
1304747ad3c4Slazypassion errors: &mut VerifierErrors,
1305220139b0Sedoardo marangoni ) -> VerifierStepResult {
1306747ad3c4Slazypassion let mut i = 0;
1307747ad3c4Slazypassion for &result in self.func.dfg.inst_results(inst) {
1308747ad3c4Slazypassion let result_type = self.func.dfg.value_type(result);
1309747ad3c4Slazypassion let expected_type = self.func.dfg.compute_result_type(inst, i, ctrl_type);
1310747ad3c4Slazypassion if let Some(expected_type) = expected_type {
1311747ad3c4Slazypassion if result_type != expected_type {
13123e5f0393SAndrew Brown errors.report((
1313747ad3c4Slazypassion inst,
13143e5f0393SAndrew Brown self.context(inst),
13153e5f0393SAndrew Brown format!(
1316a0442ea0SHamir Mahal "expected result {i} ({result}) to have type {expected_type}, found {result_type}"
13173e5f0393SAndrew Brown ),
13183e5f0393SAndrew Brown ));
1319747ad3c4Slazypassion }
1320747ad3c4Slazypassion } else {
13213e5f0393SAndrew Brown return errors.nonfatal((
13223e5f0393SAndrew Brown inst,
13233e5f0393SAndrew Brown self.context(inst),
13243e5f0393SAndrew Brown "has more result values than expected",
13253e5f0393SAndrew Brown ));
1326747ad3c4Slazypassion }
1327747ad3c4Slazypassion i += 1;
1328747ad3c4Slazypassion }
1329747ad3c4Slazypassion
1330747ad3c4Slazypassion // There aren't any more result types left.
1331747ad3c4Slazypassion if self.func.dfg.compute_result_type(inst, i, ctrl_type) != None {
13323e5f0393SAndrew Brown return errors.nonfatal((
13333e5f0393SAndrew Brown inst,
13343e5f0393SAndrew Brown self.context(inst),
13353e5f0393SAndrew Brown "has fewer result values than expected",
13363e5f0393SAndrew Brown ));
1337747ad3c4Slazypassion }
1338747ad3c4Slazypassion Ok(())
1339747ad3c4Slazypassion }
1340747ad3c4Slazypassion
typecheck_fixed_args( &self, inst: Inst, ctrl_type: Type, errors: &mut VerifierErrors, ) -> VerifierStepResult1341747ad3c4Slazypassion fn typecheck_fixed_args(
1342747ad3c4Slazypassion &self,
1343747ad3c4Slazypassion inst: Inst,
1344747ad3c4Slazypassion ctrl_type: Type,
1345747ad3c4Slazypassion errors: &mut VerifierErrors,
1346220139b0Sedoardo marangoni ) -> VerifierStepResult {
134725bf8e0eSTrevor Elliott let constraints = self.func.dfg.insts[inst].opcode().constraints();
1348747ad3c4Slazypassion
1349747ad3c4Slazypassion for (i, &arg) in self.func.dfg.inst_fixed_args(inst).iter().enumerate() {
1350747ad3c4Slazypassion let arg_type = self.func.dfg.value_type(arg);
1351747ad3c4Slazypassion match constraints.value_argument_constraint(i, ctrl_type) {
1352747ad3c4Slazypassion ResolvedConstraint::Bound(expected_type) => {
1353747ad3c4Slazypassion if arg_type != expected_type {
13543e5f0393SAndrew Brown errors.report((
1355747ad3c4Slazypassion inst,
13563e5f0393SAndrew Brown self.context(inst),
13573e5f0393SAndrew Brown format!(
1358a0442ea0SHamir Mahal "arg {i} ({arg}) has type {arg_type}, expected {expected_type}"
13593e5f0393SAndrew Brown ),
13603e5f0393SAndrew Brown ));
1361747ad3c4Slazypassion }
1362747ad3c4Slazypassion }
1363747ad3c4Slazypassion ResolvedConstraint::Free(type_set) => {
1364747ad3c4Slazypassion if !type_set.contains(arg_type) {
13653e5f0393SAndrew Brown errors.report((
1366747ad3c4Slazypassion inst,
13673e5f0393SAndrew Brown self.context(inst),
13683e5f0393SAndrew Brown format!(
1369a0442ea0SHamir Mahal "arg {i} ({arg}) with type {arg_type} failed to satisfy type set {type_set:?}"
13703e5f0393SAndrew Brown ),
13713e5f0393SAndrew Brown ));
1372747ad3c4Slazypassion }
1373747ad3c4Slazypassion }
1374747ad3c4Slazypassion }
1375747ad3c4Slazypassion }
1376747ad3c4Slazypassion Ok(())
1377747ad3c4Slazypassion }
1378747ad3c4Slazypassion
13791e6c13d8STrevor Elliott /// Typecheck both instructions that contain variable arguments like calls, and those that
13801e6c13d8STrevor Elliott /// include references to basic blocks with their arguments.
typecheck_variable_args( &self, inst: Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult1381747ad3c4Slazypassion fn typecheck_variable_args(
1382747ad3c4Slazypassion &self,
1383747ad3c4Slazypassion inst: Inst,
1384747ad3c4Slazypassion errors: &mut VerifierErrors,
1385220139b0Sedoardo marangoni ) -> VerifierStepResult {
13862c842599STrevor Elliott match &self.func.dfg.insts[inst] {
138780c147d9STrevor Elliott ir::InstructionData::Jump { destination, .. } => {
138894ec88eaSChris Fallin self.typecheck_block_call(inst, destination, BlockCallTargetType::Normal, errors)?;
1389747ad3c4Slazypassion }
1390c8a6adf8STrevor Elliott ir::InstructionData::Brif {
1391c8a6adf8STrevor Elliott blocks: [block_then, block_else],
1392c8a6adf8STrevor Elliott ..
1393c8a6adf8STrevor Elliott } => {
139494ec88eaSChris Fallin self.typecheck_block_call(inst, block_then, BlockCallTargetType::Normal, errors)?;
139594ec88eaSChris Fallin self.typecheck_block_call(inst, block_else, BlockCallTargetType::Normal, errors)?;
1396b58a197dSTrevor Elliott }
1397d99783fcSTrevor Elliott ir::InstructionData::BranchTable { table, .. } => {
1398d99783fcSTrevor Elliott for block in self.func.stencil.dfg.jump_tables[*table].all_branches() {
139994ec88eaSChris Fallin self.typecheck_block_call(inst, block, BlockCallTargetType::Normal, errors)?;
140094ec88eaSChris Fallin }
140194ec88eaSChris Fallin }
140294ec88eaSChris Fallin ir::InstructionData::TryCall { exception, .. }
140394ec88eaSChris Fallin | ir::InstructionData::TryCallIndirect { exception, .. } => {
140494ec88eaSChris Fallin let exdata = &self.func.dfg.exception_tables[*exception];
140594ec88eaSChris Fallin self.typecheck_block_call(
140694ec88eaSChris Fallin inst,
140794ec88eaSChris Fallin exdata.normal_return(),
140894ec88eaSChris Fallin BlockCallTargetType::ExNormalRet,
140994ec88eaSChris Fallin errors,
141094ec88eaSChris Fallin )?;
14114590076fSChris Fallin for item in exdata.items() {
14124590076fSChris Fallin match item {
14134590076fSChris Fallin ExceptionTableItem::Tag(_, block_call)
14144590076fSChris Fallin | ExceptionTableItem::Default(block_call) => {
14154590076fSChris Fallin self.typecheck_block_call(
14164590076fSChris Fallin inst,
14174590076fSChris Fallin &block_call,
14184590076fSChris Fallin BlockCallTargetType::Exception,
14194590076fSChris Fallin errors,
14204590076fSChris Fallin )?;
14214590076fSChris Fallin }
14224590076fSChris Fallin ExceptionTableItem::Context(_) => {}
14234590076fSChris Fallin }
1424747ad3c4Slazypassion }
1425747ad3c4Slazypassion }
14263343cf80STrevor Elliott inst => debug_assert!(!inst.opcode().is_branch()),
1427747ad3c4Slazypassion }
1428747ad3c4Slazypassion
142994ec88eaSChris Fallin match self.func.dfg.insts[inst]
143094ec88eaSChris Fallin .analyze_call(&self.func.dfg.value_lists, &self.func.dfg.exception_tables)
143194ec88eaSChris Fallin {
14321e6c13d8STrevor Elliott CallInfo::Direct(func_ref, args) => {
1433747ad3c4Slazypassion let sig_ref = self.func.dfg.ext_funcs[func_ref].signature;
1434747ad3c4Slazypassion let arg_types = self.func.dfg.signatures[sig_ref]
1435747ad3c4Slazypassion .params
1436747ad3c4Slazypassion .iter()
1437747ad3c4Slazypassion .map(|a| a.value_type);
14381e6c13d8STrevor Elliott self.typecheck_variable_args_iterator(inst, arg_types, args, errors)?;
1439747ad3c4Slazypassion }
144094ec88eaSChris Fallin CallInfo::DirectWithSig(func_ref, sig_ref, args) => {
144194ec88eaSChris Fallin let expected_sig_ref = self.func.dfg.ext_funcs[func_ref].signature;
144294ec88eaSChris Fallin let sigdata = &self.func.dfg.signatures;
144394ec88eaSChris Fallin // Compare signatures by value, not by ID -- any
144494ec88eaSChris Fallin // equivalent signature ID is acceptable.
144594ec88eaSChris Fallin if sigdata[sig_ref] != sigdata[expected_sig_ref] {
144694ec88eaSChris Fallin errors.nonfatal((
144794ec88eaSChris Fallin inst,
144894ec88eaSChris Fallin self.context(inst),
144994ec88eaSChris Fallin format!(
145094ec88eaSChris Fallin "exception table signature {sig_ref} did not match function {func_ref}'s signature {expected_sig_ref}"
145194ec88eaSChris Fallin ),
145294ec88eaSChris Fallin ))?;
145394ec88eaSChris Fallin }
145494ec88eaSChris Fallin let arg_types = self.func.dfg.signatures[sig_ref]
145594ec88eaSChris Fallin .params
145694ec88eaSChris Fallin .iter()
145794ec88eaSChris Fallin .map(|a| a.value_type);
145894ec88eaSChris Fallin self.typecheck_variable_args_iterator(inst, arg_types, args, errors)?;
145994ec88eaSChris Fallin }
14601e6c13d8STrevor Elliott CallInfo::Indirect(sig_ref, args) => {
1461747ad3c4Slazypassion let arg_types = self.func.dfg.signatures[sig_ref]
1462747ad3c4Slazypassion .params
1463747ad3c4Slazypassion .iter()
1464747ad3c4Slazypassion .map(|a| a.value_type);
14651e6c13d8STrevor Elliott self.typecheck_variable_args_iterator(inst, arg_types, args, errors)?;
1466747ad3c4Slazypassion }
1467747ad3c4Slazypassion CallInfo::NotACall => {}
1468747ad3c4Slazypassion }
1469747ad3c4Slazypassion Ok(())
1470747ad3c4Slazypassion }
1471747ad3c4Slazypassion
typecheck_block_call( &self, inst: Inst, block: &ir::BlockCall, target_type: BlockCallTargetType, errors: &mut VerifierErrors, ) -> VerifierStepResult147280c147d9STrevor Elliott fn typecheck_block_call(
147380c147d9STrevor Elliott &self,
147480c147d9STrevor Elliott inst: Inst,
147580c147d9STrevor Elliott block: &ir::BlockCall,
147694ec88eaSChris Fallin target_type: BlockCallTargetType,
147780c147d9STrevor Elliott errors: &mut VerifierErrors,
1478220139b0Sedoardo marangoni ) -> VerifierStepResult {
147980c147d9STrevor Elliott let pool = &self.func.dfg.value_lists;
148094ec88eaSChris Fallin let block_params = self.func.dfg.block_params(block.block(pool));
148194ec88eaSChris Fallin let args = block.args(pool);
148294ec88eaSChris Fallin if args.len() != block_params.len() {
148394ec88eaSChris Fallin return errors.nonfatal((
148494ec88eaSChris Fallin inst,
148594ec88eaSChris Fallin self.context(inst),
148694ec88eaSChris Fallin format!(
148794ec88eaSChris Fallin "mismatched argument count for `{}`: got {}, expected {}",
148894ec88eaSChris Fallin self.func.dfg.display_inst(inst),
148994ec88eaSChris Fallin args.len(),
149094ec88eaSChris Fallin block_params.len(),
149194ec88eaSChris Fallin ),
149294ec88eaSChris Fallin ));
149394ec88eaSChris Fallin }
149494ec88eaSChris Fallin for (arg, param) in args.zip(block_params.iter()) {
14953932e8f1Sbjorn3 let Some(arg_ty) = self.block_call_arg_ty(arg, inst, target_type, errors)? else {
14963932e8f1Sbjorn3 continue;
14973932e8f1Sbjorn3 };
149894ec88eaSChris Fallin let param_ty = self.func.dfg.value_type(*param);
149994ec88eaSChris Fallin if arg_ty != param_ty {
150094ec88eaSChris Fallin errors.nonfatal((
150194ec88eaSChris Fallin inst,
150294ec88eaSChris Fallin self.context(inst),
150394ec88eaSChris Fallin format!("arg {arg} has type {arg_ty}, expected {param_ty}"),
150494ec88eaSChris Fallin ))?;
150594ec88eaSChris Fallin }
150694ec88eaSChris Fallin }
150794ec88eaSChris Fallin Ok(())
150880c147d9STrevor Elliott }
150980c147d9STrevor Elliott
block_call_arg_ty( &self, arg: BlockArg, inst: Inst, target_type: BlockCallTargetType, errors: &mut VerifierErrors, ) -> Result<Option<Type>, ()>151094ec88eaSChris Fallin fn block_call_arg_ty(
151194ec88eaSChris Fallin &self,
151294ec88eaSChris Fallin arg: BlockArg,
151394ec88eaSChris Fallin inst: Inst,
151494ec88eaSChris Fallin target_type: BlockCallTargetType,
151594ec88eaSChris Fallin errors: &mut VerifierErrors,
15163932e8f1Sbjorn3 ) -> Result<Option<Type>, ()> {
151794ec88eaSChris Fallin match arg {
15183932e8f1Sbjorn3 BlockArg::Value(v) => Ok(Some(self.func.dfg.value_type(v))),
151994ec88eaSChris Fallin BlockArg::TryCallRet(_) | BlockArg::TryCallExn(_) => {
152094ec88eaSChris Fallin // Get the invoked signature.
152194ec88eaSChris Fallin let et = match self.func.dfg.insts[inst].exception_table() {
152294ec88eaSChris Fallin Some(et) => et,
152394ec88eaSChris Fallin None => {
152494ec88eaSChris Fallin errors.fatal((
152594ec88eaSChris Fallin inst,
152694ec88eaSChris Fallin self.context(inst),
152794ec88eaSChris Fallin format!(
152894ec88eaSChris Fallin "`retN` block argument in block-call not on `try_call` instruction"
152994ec88eaSChris Fallin ),
153094ec88eaSChris Fallin ))?;
153194ec88eaSChris Fallin unreachable!()
153294ec88eaSChris Fallin }
153394ec88eaSChris Fallin };
153494ec88eaSChris Fallin let exdata = &self.func.dfg.exception_tables[et];
153594ec88eaSChris Fallin let sig = &self.func.dfg.signatures[exdata.signature()];
153694ec88eaSChris Fallin
153794ec88eaSChris Fallin match (arg, target_type) {
153894ec88eaSChris Fallin (BlockArg::TryCallRet(i), BlockCallTargetType::ExNormalRet)
153994ec88eaSChris Fallin if (i as usize) < sig.returns.len() =>
154094ec88eaSChris Fallin {
15413932e8f1Sbjorn3 Ok(Some(sig.returns[i as usize].value_type))
154294ec88eaSChris Fallin }
154394ec88eaSChris Fallin (BlockArg::TryCallRet(_), BlockCallTargetType::ExNormalRet) => {
154494ec88eaSChris Fallin errors.fatal((
154594ec88eaSChris Fallin inst,
154694ec88eaSChris Fallin self.context(inst),
154794ec88eaSChris Fallin format!("out-of-bounds `retN` block argument"),
154894ec88eaSChris Fallin ))?;
154994ec88eaSChris Fallin unreachable!()
155094ec88eaSChris Fallin }
155194ec88eaSChris Fallin (BlockArg::TryCallRet(_), _) => {
155294ec88eaSChris Fallin errors.fatal((
155394ec88eaSChris Fallin inst,
155494ec88eaSChris Fallin self.context(inst),
155594ec88eaSChris Fallin format!("`retN` block argument used outside normal-return target of `try_call`"),
155694ec88eaSChris Fallin ))?;
155794ec88eaSChris Fallin unreachable!()
155894ec88eaSChris Fallin }
155994ec88eaSChris Fallin (BlockArg::TryCallExn(i), BlockCallTargetType::Exception) => {
15603932e8f1Sbjorn3 if let Some(isa) = self.isa {
156194ec88eaSChris Fallin match sig
156294ec88eaSChris Fallin .call_conv
15633932e8f1Sbjorn3 .exception_payload_types(isa.pointer_type())
156494ec88eaSChris Fallin .get(i as usize)
156594ec88eaSChris Fallin {
15663932e8f1Sbjorn3 Some(ty) => Ok(Some(*ty)),
156794ec88eaSChris Fallin None => {
156894ec88eaSChris Fallin errors.fatal((
156994ec88eaSChris Fallin inst,
157094ec88eaSChris Fallin self.context(inst),
157194ec88eaSChris Fallin format!("out-of-bounds `exnN` block argument"),
157294ec88eaSChris Fallin ))?;
157394ec88eaSChris Fallin unreachable!()
157494ec88eaSChris Fallin }
157594ec88eaSChris Fallin }
15763932e8f1Sbjorn3 } else {
15773932e8f1Sbjorn3 Ok(None)
15783932e8f1Sbjorn3 }
157994ec88eaSChris Fallin }
158094ec88eaSChris Fallin (BlockArg::TryCallExn(_), _) => {
158194ec88eaSChris Fallin errors.fatal((
158294ec88eaSChris Fallin inst,
158394ec88eaSChris Fallin self.context(inst),
158494ec88eaSChris Fallin format!("`exnN` block argument used outside normal-return target of `try_call`"),
158594ec88eaSChris Fallin ))?;
158694ec88eaSChris Fallin unreachable!()
158794ec88eaSChris Fallin }
158894ec88eaSChris Fallin _ => unreachable!(),
158994ec88eaSChris Fallin }
159094ec88eaSChris Fallin }
159194ec88eaSChris Fallin }
159294ec88eaSChris Fallin }
159394ec88eaSChris Fallin
typecheck_variable_args_iterator( &self, inst: Inst, iter: impl ExactSizeIterator<Item = Type>, variable_args: &[Value], errors: &mut VerifierErrors, ) -> VerifierStepResult159494ec88eaSChris Fallin fn typecheck_variable_args_iterator(
1595747ad3c4Slazypassion &self,
1596747ad3c4Slazypassion inst: Inst,
159794ec88eaSChris Fallin iter: impl ExactSizeIterator<Item = Type>,
15981e6c13d8STrevor Elliott variable_args: &[Value],
1599747ad3c4Slazypassion errors: &mut VerifierErrors,
1600220139b0Sedoardo marangoni ) -> VerifierStepResult {
1601747ad3c4Slazypassion let mut i = 0;
1602747ad3c4Slazypassion
1603747ad3c4Slazypassion for expected_type in iter {
1604747ad3c4Slazypassion if i >= variable_args.len() {
1605747ad3c4Slazypassion // Result count mismatch handled below, we want the full argument count first though
1606747ad3c4Slazypassion i += 1;
1607747ad3c4Slazypassion continue;
1608747ad3c4Slazypassion }
1609747ad3c4Slazypassion let arg = variable_args[i];
1610747ad3c4Slazypassion let arg_type = self.func.dfg.value_type(arg);
1611747ad3c4Slazypassion if expected_type != arg_type {
16123e5f0393SAndrew Brown errors.report((
1613747ad3c4Slazypassion inst,
16143e5f0393SAndrew Brown self.context(inst),
16153e5f0393SAndrew Brown format!(
1616747ad3c4Slazypassion "arg {} ({}) has type {}, expected {}",
16173e5f0393SAndrew Brown i, variable_args[i], arg_type, expected_type
16183e5f0393SAndrew Brown ),
16193e5f0393SAndrew Brown ));
1620747ad3c4Slazypassion }
1621747ad3c4Slazypassion i += 1;
1622747ad3c4Slazypassion }
1623747ad3c4Slazypassion if i != variable_args.len() {
16243e5f0393SAndrew Brown return errors.nonfatal((
1625747ad3c4Slazypassion inst,
16263e5f0393SAndrew Brown self.context(inst),
1627838f2f46SAndrew Brown format!(
1628747ad3c4Slazypassion "mismatched argument count for `{}`: got {}, expected {}",
162943a86f14SBenjamin Bouvier self.func.dfg.display_inst(inst),
1630747ad3c4Slazypassion variable_args.len(),
1631838f2f46SAndrew Brown i,
1632838f2f46SAndrew Brown ),
16333e5f0393SAndrew Brown ));
1634747ad3c4Slazypassion }
1635747ad3c4Slazypassion Ok(())
1636747ad3c4Slazypassion }
1637747ad3c4Slazypassion
typecheck_return(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult1638220139b0Sedoardo marangoni fn typecheck_return(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult {
1639bdfb7465SNick Fitzgerald match self.func.dfg.insts[inst] {
1640bdfb7465SNick Fitzgerald ir::InstructionData::MultiAry {
1641bdfb7465SNick Fitzgerald opcode: Opcode::Return,
1642bdfb7465SNick Fitzgerald args,
1643bdfb7465SNick Fitzgerald } => {
1644bdfb7465SNick Fitzgerald let types = args
1645bdfb7465SNick Fitzgerald .as_slice(&self.func.dfg.value_lists)
1646bdfb7465SNick Fitzgerald .iter()
1647bdfb7465SNick Fitzgerald .map(|v| self.func.dfg.value_type(*v));
1648bdfb7465SNick Fitzgerald self.typecheck_return_types(
1649bdfb7465SNick Fitzgerald inst,
1650bdfb7465SNick Fitzgerald types,
1651bdfb7465SNick Fitzgerald errors,
1652bdfb7465SNick Fitzgerald "arguments of return must match function signature",
1653bdfb7465SNick Fitzgerald )?;
1654bdfb7465SNick Fitzgerald }
1655bdfb7465SNick Fitzgerald ir::InstructionData::Call {
1656bdfb7465SNick Fitzgerald opcode: Opcode::ReturnCall,
1657bdfb7465SNick Fitzgerald func_ref,
1658bdfb7465SNick Fitzgerald ..
1659bdfb7465SNick Fitzgerald } => {
1660bdfb7465SNick Fitzgerald let sig_ref = self.func.dfg.ext_funcs[func_ref].signature;
1661bdfb7465SNick Fitzgerald self.typecheck_tail_call(inst, sig_ref, errors)?;
1662bdfb7465SNick Fitzgerald }
1663bdfb7465SNick Fitzgerald ir::InstructionData::CallIndirect {
1664bdfb7465SNick Fitzgerald opcode: Opcode::ReturnCallIndirect,
1665bdfb7465SNick Fitzgerald sig_ref,
1666bdfb7465SNick Fitzgerald ..
1667bdfb7465SNick Fitzgerald } => {
1668bdfb7465SNick Fitzgerald self.typecheck_tail_call(inst, sig_ref, errors)?;
1669bdfb7465SNick Fitzgerald }
1670bdfb7465SNick Fitzgerald inst => debug_assert!(!inst.opcode().is_return()),
1671bdfb7465SNick Fitzgerald }
1672bdfb7465SNick Fitzgerald Ok(())
1673bdfb7465SNick Fitzgerald }
1674bdfb7465SNick Fitzgerald
typecheck_tail_call( &self, inst: Inst, sig_ref: SigRef, errors: &mut VerifierErrors, ) -> VerifierStepResult1675bdfb7465SNick Fitzgerald fn typecheck_tail_call(
1676bdfb7465SNick Fitzgerald &self,
1677bdfb7465SNick Fitzgerald inst: Inst,
1678bdfb7465SNick Fitzgerald sig_ref: SigRef,
1679bdfb7465SNick Fitzgerald errors: &mut VerifierErrors,
1680220139b0Sedoardo marangoni ) -> VerifierStepResult {
1681bdfb7465SNick Fitzgerald let signature = &self.func.dfg.signatures[sig_ref];
1682bdfb7465SNick Fitzgerald let cc = signature.call_conv;
1683bdfb7465SNick Fitzgerald if !cc.supports_tail_calls() {
1684bdfb7465SNick Fitzgerald errors.report((
1685747ad3c4Slazypassion inst,
16863e5f0393SAndrew Brown self.context(inst),
1687bdfb7465SNick Fitzgerald format!("calling convention `{cc}` does not support tail calls"),
16883e5f0393SAndrew Brown ));
1689747ad3c4Slazypassion }
1690bdfb7465SNick Fitzgerald if cc != self.func.signature.call_conv {
1691bdfb7465SNick Fitzgerald errors.report((
1692bdfb7465SNick Fitzgerald inst,
1693bdfb7465SNick Fitzgerald self.context(inst),
1694bdfb7465SNick Fitzgerald "callee's calling convention must match caller",
1695bdfb7465SNick Fitzgerald ));
1696bdfb7465SNick Fitzgerald }
1697bdfb7465SNick Fitzgerald let types = signature.returns.iter().map(|param| param.value_type);
1698bdfb7465SNick Fitzgerald self.typecheck_return_types(inst, types, errors, "results of callee must match caller")?;
1699bdfb7465SNick Fitzgerald Ok(())
1700bdfb7465SNick Fitzgerald }
1701bdfb7465SNick Fitzgerald
typecheck_return_types( &self, inst: Inst, actual_types: impl ExactSizeIterator<Item = Type>, errors: &mut VerifierErrors, message: &str, ) -> VerifierStepResult1702bdfb7465SNick Fitzgerald fn typecheck_return_types(
1703bdfb7465SNick Fitzgerald &self,
1704bdfb7465SNick Fitzgerald inst: Inst,
1705bdfb7465SNick Fitzgerald actual_types: impl ExactSizeIterator<Item = Type>,
1706bdfb7465SNick Fitzgerald errors: &mut VerifierErrors,
1707bdfb7465SNick Fitzgerald message: &str,
1708220139b0Sedoardo marangoni ) -> VerifierStepResult {
1709bdfb7465SNick Fitzgerald let expected_types = &self.func.signature.returns;
1710bdfb7465SNick Fitzgerald if actual_types.len() != expected_types.len() {
1711bdfb7465SNick Fitzgerald return errors.nonfatal((inst, self.context(inst), message));
1712bdfb7465SNick Fitzgerald }
1713bdfb7465SNick Fitzgerald for (i, (actual_type, &expected_type)) in actual_types.zip(expected_types).enumerate() {
1714bdfb7465SNick Fitzgerald if actual_type != expected_type.value_type {
17153e5f0393SAndrew Brown errors.report((
1716747ad3c4Slazypassion inst,
17173e5f0393SAndrew Brown self.context(inst),
17183e5f0393SAndrew Brown format!(
1719bdfb7465SNick Fitzgerald "result {i} has type {actual_type}, must match function signature of \
1720bdfb7465SNick Fitzgerald {expected_type}"
17213e5f0393SAndrew Brown ),
17223e5f0393SAndrew Brown ));
1723747ad3c4Slazypassion }
1724747ad3c4Slazypassion }
1725747ad3c4Slazypassion Ok(())
1726747ad3c4Slazypassion }
1727747ad3c4Slazypassion
1728747ad3c4Slazypassion // Check special-purpose type constraints that can't be expressed in the normal opcode
1729747ad3c4Slazypassion // constraints.
typecheck_special(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult1730220139b0Sedoardo marangoni fn typecheck_special(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult {
173125bf8e0eSTrevor Elliott match self.func.dfg.insts[inst] {
1732747ad3c4Slazypassion ir::InstructionData::UnaryGlobalValue { global_value, .. } => {
1733747ad3c4Slazypassion if let Some(isa) = self.isa {
1734747ad3c4Slazypassion let inst_type = self.func.dfg.value_type(self.func.dfg.first_result(inst));
1735747ad3c4Slazypassion let global_type = self.func.global_values[global_value].global_type(isa);
1736747ad3c4Slazypassion if inst_type != global_type {
17373e5f0393SAndrew Brown return errors.nonfatal((
17383e5f0393SAndrew Brown inst, self.context(inst),
1739838f2f46SAndrew Brown format!(
1740a0442ea0SHamir Mahal "global_value instruction with type {inst_type} references global value with type {global_type}"
17413e5f0393SAndrew Brown )),
1742747ad3c4Slazypassion );
1743747ad3c4Slazypassion }
1744747ad3c4Slazypassion }
1745747ad3c4Slazypassion }
1746747ad3c4Slazypassion _ => {}
1747747ad3c4Slazypassion }
1748747ad3c4Slazypassion Ok(())
1749747ad3c4Slazypassion }
1750747ad3c4Slazypassion
cfg_integrity( &self, cfg: &ControlFlowGraph, errors: &mut VerifierErrors, ) -> VerifierStepResult1751747ad3c4Slazypassion fn cfg_integrity(
1752747ad3c4Slazypassion &self,
1753747ad3c4Slazypassion cfg: &ControlFlowGraph,
1754747ad3c4Slazypassion errors: &mut VerifierErrors,
1755220139b0Sedoardo marangoni ) -> VerifierStepResult {
1756832666c4SRyan Hunt let mut expected_succs = BTreeSet::<Block>::new();
1757832666c4SRyan Hunt let mut got_succs = BTreeSet::<Block>::new();
1758747ad3c4Slazypassion let mut expected_preds = BTreeSet::<Inst>::new();
1759747ad3c4Slazypassion let mut got_preds = BTreeSet::<Inst>::new();
1760747ad3c4Slazypassion
1761832666c4SRyan Hunt for block in self.func.layout.blocks() {
1762832666c4SRyan Hunt expected_succs.extend(self.expected_cfg.succ_iter(block));
1763832666c4SRyan Hunt got_succs.extend(cfg.succ_iter(block));
1764747ad3c4Slazypassion
1765832666c4SRyan Hunt let missing_succs: Vec<Block> =
1766832666c4SRyan Hunt expected_succs.difference(&got_succs).cloned().collect();
1767747ad3c4Slazypassion if !missing_succs.is_empty() {
17683e5f0393SAndrew Brown errors.report((
1769832666c4SRyan Hunt block,
1770a0442ea0SHamir Mahal format!("cfg lacked the following successor(s) {missing_succs:?}"),
17713e5f0393SAndrew Brown ));
1772747ad3c4Slazypassion continue;
1773747ad3c4Slazypassion }
1774747ad3c4Slazypassion
1775832666c4SRyan Hunt let excess_succs: Vec<Block> = got_succs.difference(&expected_succs).cloned().collect();
1776747ad3c4Slazypassion if !excess_succs.is_empty() {
17773e5f0393SAndrew Brown errors.report((
1778832666c4SRyan Hunt block,
1779a0442ea0SHamir Mahal format!("cfg had unexpected successor(s) {excess_succs:?}"),
17803e5f0393SAndrew Brown ));
1781747ad3c4Slazypassion continue;
1782747ad3c4Slazypassion }
1783747ad3c4Slazypassion
1784747ad3c4Slazypassion expected_preds.extend(
1785747ad3c4Slazypassion self.expected_cfg
1786832666c4SRyan Hunt .pred_iter(block)
1787832666c4SRyan Hunt .map(|BlockPredecessor { inst, .. }| inst),
1788747ad3c4Slazypassion );
1789832666c4SRyan Hunt got_preds.extend(
1790832666c4SRyan Hunt cfg.pred_iter(block)
1791832666c4SRyan Hunt .map(|BlockPredecessor { inst, .. }| inst),
1792832666c4SRyan Hunt );
1793747ad3c4Slazypassion
1794747ad3c4Slazypassion let missing_preds: Vec<Inst> = expected_preds.difference(&got_preds).cloned().collect();
1795747ad3c4Slazypassion if !missing_preds.is_empty() {
17963e5f0393SAndrew Brown errors.report((
1797832666c4SRyan Hunt block,
1798a0442ea0SHamir Mahal format!("cfg lacked the following predecessor(s) {missing_preds:?}"),
17993e5f0393SAndrew Brown ));
1800747ad3c4Slazypassion continue;
1801747ad3c4Slazypassion }
1802747ad3c4Slazypassion
1803747ad3c4Slazypassion let excess_preds: Vec<Inst> = got_preds.difference(&expected_preds).cloned().collect();
1804747ad3c4Slazypassion if !excess_preds.is_empty() {
18053e5f0393SAndrew Brown errors.report((
1806832666c4SRyan Hunt block,
1807a0442ea0SHamir Mahal format!("cfg had unexpected predecessor(s) {excess_preds:?}"),
18083e5f0393SAndrew Brown ));
1809747ad3c4Slazypassion continue;
1810747ad3c4Slazypassion }
1811747ad3c4Slazypassion
1812747ad3c4Slazypassion expected_succs.clear();
1813747ad3c4Slazypassion got_succs.clear();
1814747ad3c4Slazypassion expected_preds.clear();
1815747ad3c4Slazypassion got_preds.clear();
1816747ad3c4Slazypassion }
1817747ad3c4Slazypassion errors.as_result()
1818747ad3c4Slazypassion }
1819747ad3c4Slazypassion
immediate_constraints(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult1820220139b0Sedoardo marangoni fn immediate_constraints(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult {
182125bf8e0eSTrevor Elliott let inst_data = &self.func.dfg.insts[inst];
1822747ad3c4Slazypassion
18239b852fdeSAndrew Brown match *inst_data {
1824bd6fe11cSAndrew Brown ir::InstructionData::Store { flags, .. } => {
18259b852fdeSAndrew Brown if flags.readonly() {
18263e5f0393SAndrew Brown errors.fatal((
1827747ad3c4Slazypassion inst,
18283e5f0393SAndrew Brown self.context(inst),
1829838f2f46SAndrew Brown "A store instruction cannot have the `readonly` MemFlag",
18303e5f0393SAndrew Brown ))
1831747ad3c4Slazypassion } else {
1832747ad3c4Slazypassion Ok(())
1833747ad3c4Slazypassion }
1834747ad3c4Slazypassion }
1835a27a079dSAndrew Brown ir::InstructionData::BinaryImm8 {
18369b852fdeSAndrew Brown opcode: ir::instructions::Opcode::Extractlane,
1837a27a079dSAndrew Brown imm: lane,
18389b852fdeSAndrew Brown arg,
18399b852fdeSAndrew Brown ..
18409b852fdeSAndrew Brown }
18417d6e94b9SAndrew Brown | ir::InstructionData::TernaryImm8 {
18429b852fdeSAndrew Brown opcode: ir::instructions::Opcode::Insertlane,
18437d6e94b9SAndrew Brown imm: lane,
18449b852fdeSAndrew Brown args: [arg, _],
18459b852fdeSAndrew Brown ..
18469b852fdeSAndrew Brown } => {
18479b852fdeSAndrew Brown // We must be specific about the opcodes above because other instructions are using
18487d6e94b9SAndrew Brown // the same formats.
18499b852fdeSAndrew Brown let ty = self.func.dfg.value_type(arg);
1850a2d49ebfSSam Parker if lane as u32 >= ty.lane_count() {
18513e5f0393SAndrew Brown errors.fatal((
18529b852fdeSAndrew Brown inst,
18533e5f0393SAndrew Brown self.context(inst),
1854a0442ea0SHamir Mahal format!("The lane {lane} does not index into the type {ty}",),
18553e5f0393SAndrew Brown ))
18569b852fdeSAndrew Brown } else {
18579b852fdeSAndrew Brown Ok(())
18589b852fdeSAndrew Brown }
18599b852fdeSAndrew Brown }
18607956dc6bSAlex Crichton ir::InstructionData::Shuffle {
18617956dc6bSAlex Crichton opcode: ir::instructions::Opcode::Shuffle,
18627956dc6bSAlex Crichton imm,
18637956dc6bSAlex Crichton ..
18647956dc6bSAlex Crichton } => {
18657956dc6bSAlex Crichton let imm = self.func.dfg.immediates.get(imm).unwrap().as_slice();
18667956dc6bSAlex Crichton if imm.len() != 16 {
18677956dc6bSAlex Crichton errors.fatal((
18687956dc6bSAlex Crichton inst,
18697956dc6bSAlex Crichton self.context(inst),
18707956dc6bSAlex Crichton format!("the shuffle immediate wasn't 16-bytes long"),
18717956dc6bSAlex Crichton ))
18727956dc6bSAlex Crichton } else if let Some(i) = imm.iter().find(|i| **i >= 32) {
18737956dc6bSAlex Crichton errors.fatal((
18747956dc6bSAlex Crichton inst,
18757956dc6bSAlex Crichton self.context(inst),
18767956dc6bSAlex Crichton format!("shuffle immediate index {i} is larger than the maximum 31"),
18777956dc6bSAlex Crichton ))
18787956dc6bSAlex Crichton } else {
18797956dc6bSAlex Crichton Ok(())
18807956dc6bSAlex Crichton }
18817956dc6bSAlex Crichton }
18829b852fdeSAndrew Brown _ => Ok(()),
18839b852fdeSAndrew Brown }
18849b852fdeSAndrew Brown }
1885747ad3c4Slazypassion
iconst_bounds(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult1886220139b0Sedoardo marangoni fn iconst_bounds(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult {
1887cd33a1b5STimothée Jourde use crate::ir::instructions::InstructionData::UnaryImm;
1888cd33a1b5STimothée Jourde
1889cd33a1b5STimothée Jourde let inst_data = &self.func.dfg.insts[inst];
1890cd33a1b5STimothée Jourde if let UnaryImm {
1891cd33a1b5STimothée Jourde opcode: Opcode::Iconst,
1892cd33a1b5STimothée Jourde imm,
1893cd33a1b5STimothée Jourde } = inst_data
1894cd33a1b5STimothée Jourde {
1895cd33a1b5STimothée Jourde let ctrl_typevar = self.func.dfg.ctrl_typevar(inst);
1896cd33a1b5STimothée Jourde let bounds_mask = match ctrl_typevar {
1897cd33a1b5STimothée Jourde types::I8 => u8::MAX.into(),
1898cd33a1b5STimothée Jourde types::I16 => u16::MAX.into(),
1899cd33a1b5STimothée Jourde types::I32 => u32::MAX.into(),
1900cd33a1b5STimothée Jourde types::I64 => u64::MAX,
1901cd33a1b5STimothée Jourde _ => unreachable!(),
1902cd33a1b5STimothée Jourde };
1903cd33a1b5STimothée Jourde
1904cd33a1b5STimothée Jourde let value = imm.bits() as u64;
1905cd33a1b5STimothée Jourde if value & bounds_mask != value {
1906cd33a1b5STimothée Jourde errors.fatal((
1907cd33a1b5STimothée Jourde inst,
1908cd33a1b5STimothée Jourde self.context(inst),
1909cd33a1b5STimothée Jourde "constant immediate is out of bounds",
1910cd33a1b5STimothée Jourde ))
1911cd33a1b5STimothée Jourde } else {
1912cd33a1b5STimothée Jourde Ok(())
1913cd33a1b5STimothée Jourde }
1914cd33a1b5STimothée Jourde } else {
1915cd33a1b5STimothée Jourde Ok(())
1916cd33a1b5STimothée Jourde }
1917cd33a1b5STimothée Jourde }
1918cd33a1b5STimothée Jourde
typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult1919220139b0Sedoardo marangoni fn typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult {
19209556cb19SAfonso Bordado let params = self
19219556cb19SAfonso Bordado .func
19221e74d011SWander Lairson Costa .signature
19231e74d011SWander Lairson Costa .params
19241e74d011SWander Lairson Costa .iter()
19251e74d011SWander Lairson Costa .enumerate()
19269556cb19SAfonso Bordado .map(|p| (true, p));
19279556cb19SAfonso Bordado let returns = self
19289556cb19SAfonso Bordado .func
19299556cb19SAfonso Bordado .signature
19309556cb19SAfonso Bordado .returns
19319556cb19SAfonso Bordado .iter()
19329556cb19SAfonso Bordado .enumerate()
19339556cb19SAfonso Bordado .map(|p| (false, p));
19349556cb19SAfonso Bordado
19359556cb19SAfonso Bordado for (is_argument, (i, param)) in params.chain(returns) {
19369556cb19SAfonso Bordado let is_return = !is_argument;
19379556cb19SAfonso Bordado let item = if is_argument {
19389556cb19SAfonso Bordado "Parameter"
19399556cb19SAfonso Bordado } else {
19409556cb19SAfonso Bordado "Return value"
19419556cb19SAfonso Bordado };
19429556cb19SAfonso Bordado
19439556cb19SAfonso Bordado if param.value_type == types::INVALID {
19443e5f0393SAndrew Brown errors.report((
19451e74d011SWander Lairson Costa AnyEntity::Function,
19469556cb19SAfonso Bordado format!("{item} at position {i} has an invalid type"),
19473e5f0393SAndrew Brown ));
19489556cb19SAfonso Bordado }
19491e74d011SWander Lairson Costa
19509556cb19SAfonso Bordado if let ArgumentPurpose::StructArgument(_) = param.purpose {
19519556cb19SAfonso Bordado if is_return {
19523e5f0393SAndrew Brown errors.report((
19531e74d011SWander Lairson Costa AnyEntity::Function,
19549556cb19SAfonso Bordado format!("{item} at position {i} can't be an struct argument"),
19554431ac11Sbjorn3 ))
19564431ac11Sbjorn3 }
19579556cb19SAfonso Bordado }
19589556cb19SAfonso Bordado
19599556cb19SAfonso Bordado let ty_allows_extension = param.value_type.is_int();
19609556cb19SAfonso Bordado let has_extension = param.extension != ArgumentExtension::None;
19619556cb19SAfonso Bordado if !ty_allows_extension && has_extension {
19629556cb19SAfonso Bordado errors.report((
19639556cb19SAfonso Bordado AnyEntity::Function,
19649556cb19SAfonso Bordado format!(
19659556cb19SAfonso Bordado "{} at position {} has invalid extension {:?}",
19669556cb19SAfonso Bordado item, i, param.extension
19679556cb19SAfonso Bordado ),
19689556cb19SAfonso Bordado ));
19699556cb19SAfonso Bordado }
19709556cb19SAfonso Bordado }
19714431ac11Sbjorn3
197290ac295eSAlex Crichton if errors.has_error() { Err(()) } else { Ok(()) }
19731e74d011SWander Lairson Costa }
19741e74d011SWander Lairson Costa
verify_try_call_handler_index( &self, inst: Inst, block: Block, index_imm: i64, errors: &mut VerifierErrors, ) -> VerifierStepResult19754c01ee2fSChris Fallin fn verify_try_call_handler_index(
19764c01ee2fSChris Fallin &self,
19774c01ee2fSChris Fallin inst: Inst,
19784c01ee2fSChris Fallin block: Block,
19794c01ee2fSChris Fallin index_imm: i64,
19804c01ee2fSChris Fallin errors: &mut VerifierErrors,
19814c01ee2fSChris Fallin ) -> VerifierStepResult {
19824c01ee2fSChris Fallin if index_imm < 0 {
19834c01ee2fSChris Fallin return errors.fatal((
19844c01ee2fSChris Fallin inst,
19854c01ee2fSChris Fallin format!("exception handler index {index_imm} cannot be negative"),
19864c01ee2fSChris Fallin ));
19874c01ee2fSChris Fallin }
19884c01ee2fSChris Fallin let Ok(index) = usize::try_from(index_imm) else {
19894c01ee2fSChris Fallin return errors.fatal((
19904c01ee2fSChris Fallin inst,
19914c01ee2fSChris Fallin format!("exception handler index {index_imm} is out-of-range"),
19924c01ee2fSChris Fallin ));
19934c01ee2fSChris Fallin };
19944c01ee2fSChris Fallin let Some(terminator) = self.func.layout.last_inst(block) else {
19954c01ee2fSChris Fallin return errors.fatal((
19964c01ee2fSChris Fallin inst,
19974c01ee2fSChris Fallin format!("referenced block {block} does not have a terminator"),
19984c01ee2fSChris Fallin ));
19994c01ee2fSChris Fallin };
20004c01ee2fSChris Fallin let Some(et) = self.func.dfg.insts[terminator].exception_table() else {
20014c01ee2fSChris Fallin return errors.fatal((
20024c01ee2fSChris Fallin inst,
20034c01ee2fSChris Fallin format!("referenced block {block} does not end in a try_call"),
20044c01ee2fSChris Fallin ));
20054c01ee2fSChris Fallin };
20064c01ee2fSChris Fallin
20074c01ee2fSChris Fallin let etd = &self.func.dfg.exception_tables[et];
20084c01ee2fSChris Fallin // The exception table's out-edges consist of all exceptional
20094c01ee2fSChris Fallin // edges first, followed by the normal return last. For N
20104c01ee2fSChris Fallin // out-edges, there are N-1 exception handlers that can be
20114c01ee2fSChris Fallin // selected.
20124c01ee2fSChris Fallin let num_exceptional_edges = etd.all_branches().len() - 1;
20134c01ee2fSChris Fallin if index >= num_exceptional_edges {
20144c01ee2fSChris Fallin return errors.fatal((
20154c01ee2fSChris Fallin inst,
20164c01ee2fSChris Fallin format!("exception handler index {index_imm} is out-of-range"),
20174c01ee2fSChris Fallin ));
20184c01ee2fSChris Fallin }
20194c01ee2fSChris Fallin
20204c01ee2fSChris Fallin Ok(())
20214c01ee2fSChris Fallin }
20224c01ee2fSChris Fallin
debug_tags(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult2023a3d6e407SChris Fallin pub fn debug_tags(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult {
2024a3d6e407SChris Fallin // Tags can only be present on calls and sequence points.
2025a3d6e407SChris Fallin let op = self.func.dfg.insts[inst].opcode();
2026a3d6e407SChris Fallin let tags_allowed = op.is_call() || op == Opcode::SequencePoint;
2027a3d6e407SChris Fallin let has_tags = self.func.debug_tags.has(inst);
2028a3d6e407SChris Fallin if has_tags && !tags_allowed {
2029a3d6e407SChris Fallin return errors.fatal((
2030a3d6e407SChris Fallin inst,
2031a3d6e407SChris Fallin "debug tags present on non-call, non-sequence point instruction".to_string(),
2032a3d6e407SChris Fallin ));
2033a3d6e407SChris Fallin }
2034a3d6e407SChris Fallin
2035a3d6e407SChris Fallin Ok(())
2036a3d6e407SChris Fallin }
2037a3d6e407SChris Fallin
verify_signature( &self, sig: &Signature, entity: impl Into<AnyEntity>, errors: &mut VerifierErrors, ) -> VerifierStepResult2038c3c2ee20SChris Fallin fn verify_signature(
2039c3c2ee20SChris Fallin &self,
2040c3c2ee20SChris Fallin sig: &Signature,
2041c3c2ee20SChris Fallin entity: impl Into<AnyEntity>,
2042c3c2ee20SChris Fallin errors: &mut VerifierErrors,
2043c3c2ee20SChris Fallin ) -> VerifierStepResult {
2044c3c2ee20SChris Fallin match sig.call_conv {
2045c3c2ee20SChris Fallin CallConv::PreserveAll => {
2046c3c2ee20SChris Fallin if !sig.returns.is_empty() {
2047c3c2ee20SChris Fallin errors.fatal((
2048c3c2ee20SChris Fallin entity,
2049c3c2ee20SChris Fallin "Signature with `preserve_all` ABI cannot have return values".to_string(),
2050c3c2ee20SChris Fallin ))?;
2051c3c2ee20SChris Fallin }
2052c3c2ee20SChris Fallin }
2053c3c2ee20SChris Fallin _ => {}
2054c3c2ee20SChris Fallin }
2055c3c2ee20SChris Fallin Ok(())
2056c3c2ee20SChris Fallin }
2057c3c2ee20SChris Fallin
verify_signatures(&self, errors: &mut VerifierErrors) -> VerifierStepResult2058c3c2ee20SChris Fallin fn verify_signatures(&self, errors: &mut VerifierErrors) -> VerifierStepResult {
2059c3c2ee20SChris Fallin // Verify this function's own signature.
2060c3c2ee20SChris Fallin self.verify_signature(&self.func.signature, AnyEntity::Function, errors)?;
2061c3c2ee20SChris Fallin // Verify signatures referenced by any extfunc, using that
2062c3c2ee20SChris Fallin // extfunc as the entity to which to attach the error.
2063c3c2ee20SChris Fallin for (func, funcdata) in &self.func.dfg.ext_funcs {
2064c3c2ee20SChris Fallin // Non-contiguous func entities result in placeholders
2065c3c2ee20SChris Fallin // with invalid signatures; skip them.
2066c3c2ee20SChris Fallin if !funcdata.signature.is_reserved_value() {
2067c3c2ee20SChris Fallin self.verify_signature(&self.func.dfg.signatures[funcdata.signature], func, errors)?;
2068c3c2ee20SChris Fallin }
2069c3c2ee20SChris Fallin }
2070c3c2ee20SChris Fallin // Verify all signatures, including those only used by
2071c3c2ee20SChris Fallin // e.g. indirect calls. Technically this re-verifies
2072c3c2ee20SChris Fallin // signatures verified above but we want the first pass to
2073c3c2ee20SChris Fallin // attach errors to funcrefs and we also need to verify all
2074c3c2ee20SChris Fallin // defined signatures.
2075c3c2ee20SChris Fallin for (sig, sigdata) in &self.func.dfg.signatures {
2076c3c2ee20SChris Fallin self.verify_signature(sigdata, sig, errors)?;
2077c3c2ee20SChris Fallin }
2078c3c2ee20SChris Fallin Ok(())
2079c3c2ee20SChris Fallin }
2080c3c2ee20SChris Fallin
run(&self, errors: &mut VerifierErrors) -> VerifierStepResult2081220139b0Sedoardo marangoni pub fn run(&self, errors: &mut VerifierErrors) -> VerifierStepResult {
2082747ad3c4Slazypassion self.verify_global_values(errors)?;
2083747ad3c4Slazypassion self.typecheck_entry_block_params(errors)?;
2084953f83e6SChris Fallin self.check_entry_not_cold(errors)?;
20851e74d011SWander Lairson Costa self.typecheck_function_signature(errors)?;
2086c3c2ee20SChris Fallin self.verify_signatures(errors)?;
2087747ad3c4Slazypassion
2088832666c4SRyan Hunt for block in self.func.layout.blocks() {
2089832666c4SRyan Hunt if self.func.layout.first_inst(block).is_none() {
2090a0442ea0SHamir Mahal return errors.fatal((block, format!("{block} cannot be empty")));
2091250ea0e5Sdata-pup }
2092832666c4SRyan Hunt for inst in self.func.layout.block_insts(block) {
2093fc5fc675SNick Fitzgerald crate::trace!("verifying {inst:?}: {}", self.func.dfg.display_inst(inst));
2094832666c4SRyan Hunt self.block_integrity(block, inst, errors)?;
2095747ad3c4Slazypassion self.instruction_integrity(inst, errors)?;
2096747ad3c4Slazypassion self.typecheck(inst, errors)?;
2097747ad3c4Slazypassion self.immediate_constraints(inst, errors)?;
2098cd33a1b5STimothée Jourde self.iconst_bounds(inst, errors)?;
2099a3d6e407SChris Fallin self.debug_tags(inst, errors)?;
2100747ad3c4Slazypassion }
21019b97ddf2SSean Stangl
2102832666c4SRyan Hunt self.encodable_as_bb(block, errors)?;
2103747ad3c4Slazypassion }
2104747ad3c4Slazypassion
2105838f2f46SAndrew Brown if !errors.is_empty() {
21064283d211SNick Fitzgerald log::warn!(
2107838f2f46SAndrew Brown "Found verifier errors in function:\n{}",
210843a86f14SBenjamin Bouvier pretty_verifier_error(self.func, None, errors.clone())
2109838f2f46SAndrew Brown );
2110838f2f46SAndrew Brown }
2111838f2f46SAndrew Brown
2112747ad3c4Slazypassion Ok(())
2113747ad3c4Slazypassion }
2114747ad3c4Slazypassion }
2115747ad3c4Slazypassion
2116747ad3c4Slazypassion #[cfg(test)]
2117747ad3c4Slazypassion mod tests {
2118747ad3c4Slazypassion use super::{Verifier, VerifierError, VerifierErrors};
2119747ad3c4Slazypassion use crate::ir::instructions::{InstructionData, Opcode};
212090ac295eSAlex Crichton use crate::ir::{AbiParam, Function, Type, types};
2121747ad3c4Slazypassion use crate::settings;
2122747ad3c4Slazypassion
2123747ad3c4Slazypassion macro_rules! assert_err_with_msg {
2124747ad3c4Slazypassion ($e:expr, $msg:expr) => {
2125747ad3c4Slazypassion match $e.0.get(0) {
2126747ad3c4Slazypassion None => panic!("Expected an error"),
2127747ad3c4Slazypassion Some(&VerifierError { ref message, .. }) => {
2128747ad3c4Slazypassion if !message.contains($msg) {
2129747ad3c4Slazypassion #[cfg(feature = "std")]
21308cd64e3eSChris Fallin panic!("'{}' did not contain the substring '{}'", message, $msg);
2131747ad3c4Slazypassion #[cfg(not(feature = "std"))]
2132747ad3c4Slazypassion panic!("error message did not contain the expected substring");
2133747ad3c4Slazypassion }
2134747ad3c4Slazypassion }
2135747ad3c4Slazypassion }
2136747ad3c4Slazypassion };
2137747ad3c4Slazypassion }
2138747ad3c4Slazypassion
2139747ad3c4Slazypassion #[test]
empty()2140747ad3c4Slazypassion fn empty() {
2141747ad3c4Slazypassion let func = Function::new();
2142747ad3c4Slazypassion let flags = &settings::Flags::new(settings::builder());
2143747ad3c4Slazypassion let verifier = Verifier::new(&func, flags.into());
2144747ad3c4Slazypassion let mut errors = VerifierErrors::default();
2145747ad3c4Slazypassion
2146747ad3c4Slazypassion assert_eq!(verifier.run(&mut errors), Ok(()));
2147747ad3c4Slazypassion assert!(errors.0.is_empty());
2148747ad3c4Slazypassion }
2149747ad3c4Slazypassion
2150747ad3c4Slazypassion #[test]
bad_instruction_format()2151747ad3c4Slazypassion fn bad_instruction_format() {
2152747ad3c4Slazypassion let mut func = Function::new();
2153832666c4SRyan Hunt let block0 = func.dfg.make_block();
2154832666c4SRyan Hunt func.layout.append_block(block0);
2155747ad3c4Slazypassion let nullary_with_bad_opcode = func.dfg.make_inst(InstructionData::UnaryImm {
2156747ad3c4Slazypassion opcode: Opcode::F32const,
2157747ad3c4Slazypassion imm: 0.into(),
2158747ad3c4Slazypassion });
2159832666c4SRyan Hunt func.layout.append_inst(nullary_with_bad_opcode, block0);
21601e6c13d8STrevor Elliott let destination = func.dfg.block_call(block0, &[]);
21618a9b1a90SBenjamin Bouvier func.stencil.layout.append_inst(
21628a9b1a90SBenjamin Bouvier func.stencil.dfg.make_inst(InstructionData::Jump {
2163747ad3c4Slazypassion opcode: Opcode::Jump,
21641e6c13d8STrevor Elliott destination,
2165747ad3c4Slazypassion }),
2166832666c4SRyan Hunt block0,
2167747ad3c4Slazypassion );
2168747ad3c4Slazypassion let flags = &settings::Flags::new(settings::builder());
2169747ad3c4Slazypassion let verifier = Verifier::new(&func, flags.into());
2170747ad3c4Slazypassion let mut errors = VerifierErrors::default();
2171747ad3c4Slazypassion
2172747ad3c4Slazypassion let _ = verifier.run(&mut errors);
2173747ad3c4Slazypassion
2174747ad3c4Slazypassion assert_err_with_msg!(errors, "instruction format");
2175747ad3c4Slazypassion }
21761e74d011SWander Lairson Costa
test_iconst_bounds(immediate: i64, ctrl_typevar: Type) -> VerifierErrors2177cd33a1b5STimothée Jourde fn test_iconst_bounds(immediate: i64, ctrl_typevar: Type) -> VerifierErrors {
2178cd33a1b5STimothée Jourde let mut func = Function::new();
2179cd33a1b5STimothée Jourde let block0 = func.dfg.make_block();
2180cd33a1b5STimothée Jourde func.layout.append_block(block0);
2181cd33a1b5STimothée Jourde
2182cd33a1b5STimothée Jourde let test_inst = func.dfg.make_inst(InstructionData::UnaryImm {
2183cd33a1b5STimothée Jourde opcode: Opcode::Iconst,
2184cd33a1b5STimothée Jourde imm: immediate.into(),
2185cd33a1b5STimothée Jourde });
2186cd33a1b5STimothée Jourde
2187cd33a1b5STimothée Jourde let end_inst = func.dfg.make_inst(InstructionData::MultiAry {
2188cd33a1b5STimothée Jourde opcode: Opcode::Return,
2189cd33a1b5STimothée Jourde args: Default::default(),
2190cd33a1b5STimothée Jourde });
2191cd33a1b5STimothée Jourde
2192d02f895fSJamey Sharp func.dfg.make_inst_results(test_inst, ctrl_typevar);
2193cd33a1b5STimothée Jourde func.layout.append_inst(test_inst, block0);
2194cd33a1b5STimothée Jourde func.layout.append_inst(end_inst, block0);
2195cd33a1b5STimothée Jourde
2196cd33a1b5STimothée Jourde let flags = &settings::Flags::new(settings::builder());
2197cd33a1b5STimothée Jourde let verifier = Verifier::new(&func, flags.into());
2198cd33a1b5STimothée Jourde let mut errors = VerifierErrors::default();
2199cd33a1b5STimothée Jourde
2200cd33a1b5STimothée Jourde let _ = verifier.run(&mut errors);
2201cd33a1b5STimothée Jourde errors
2202cd33a1b5STimothée Jourde }
2203cd33a1b5STimothée Jourde
test_iconst_bounds_err(immediate: i64, ctrl_typevar: Type)2204cd33a1b5STimothée Jourde fn test_iconst_bounds_err(immediate: i64, ctrl_typevar: Type) {
2205cd33a1b5STimothée Jourde assert_err_with_msg!(
2206cd33a1b5STimothée Jourde test_iconst_bounds(immediate, ctrl_typevar),
2207cd33a1b5STimothée Jourde "constant immediate is out of bounds"
2208cd33a1b5STimothée Jourde );
2209cd33a1b5STimothée Jourde }
2210cd33a1b5STimothée Jourde
test_iconst_bounds_ok(immediate: i64, ctrl_typevar: Type)2211cd33a1b5STimothée Jourde fn test_iconst_bounds_ok(immediate: i64, ctrl_typevar: Type) {
2212cd33a1b5STimothée Jourde assert!(test_iconst_bounds(immediate, ctrl_typevar).is_empty());
2213cd33a1b5STimothée Jourde }
2214cd33a1b5STimothée Jourde
2215cd33a1b5STimothée Jourde #[test]
negative_iconst_8()2216cd33a1b5STimothée Jourde fn negative_iconst_8() {
2217cd33a1b5STimothée Jourde test_iconst_bounds_err(-10, types::I8);
2218cd33a1b5STimothée Jourde }
2219cd33a1b5STimothée Jourde
2220cd33a1b5STimothée Jourde #[test]
negative_iconst_32()2221cd33a1b5STimothée Jourde fn negative_iconst_32() {
2222cd33a1b5STimothée Jourde test_iconst_bounds_err(-1, types::I32);
2223cd33a1b5STimothée Jourde }
2224cd33a1b5STimothée Jourde
2225cd33a1b5STimothée Jourde #[test]
large_iconst_8()2226cd33a1b5STimothée Jourde fn large_iconst_8() {
2227cd33a1b5STimothée Jourde test_iconst_bounds_err(1 + u8::MAX as i64, types::I8);
2228cd33a1b5STimothée Jourde }
2229cd33a1b5STimothée Jourde
2230cd33a1b5STimothée Jourde #[test]
large_iconst_16()2231cd33a1b5STimothée Jourde fn large_iconst_16() {
2232cd33a1b5STimothée Jourde test_iconst_bounds_err(10 + u16::MAX as i64, types::I16);
2233cd33a1b5STimothée Jourde }
2234cd33a1b5STimothée Jourde
2235cd33a1b5STimothée Jourde #[test]
valid_iconst_8()2236cd33a1b5STimothée Jourde fn valid_iconst_8() {
2237cd33a1b5STimothée Jourde test_iconst_bounds_ok(10, types::I8);
2238cd33a1b5STimothée Jourde }
2239cd33a1b5STimothée Jourde
2240cd33a1b5STimothée Jourde #[test]
valid_iconst_32()2241cd33a1b5STimothée Jourde fn valid_iconst_32() {
2242cd33a1b5STimothée Jourde test_iconst_bounds_ok(u32::MAX as i64, types::I32);
2243cd33a1b5STimothée Jourde }
2244cd33a1b5STimothée Jourde
22451e74d011SWander Lairson Costa #[test]
test_function_invalid_param()22461e74d011SWander Lairson Costa fn test_function_invalid_param() {
22471e74d011SWander Lairson Costa let mut func = Function::new();
22481e74d011SWander Lairson Costa func.signature.params.push(AbiParam::new(types::INVALID));
22491e74d011SWander Lairson Costa
22501e74d011SWander Lairson Costa let mut errors = VerifierErrors::default();
22511e74d011SWander Lairson Costa let flags = &settings::Flags::new(settings::builder());
22521e74d011SWander Lairson Costa let verifier = Verifier::new(&func, flags.into());
22531e74d011SWander Lairson Costa
22541e74d011SWander Lairson Costa let _ = verifier.typecheck_function_signature(&mut errors);
22551e74d011SWander Lairson Costa assert_err_with_msg!(errors, "Parameter at position 0 has an invalid type");
22561e74d011SWander Lairson Costa }
22571e74d011SWander Lairson Costa
22581e74d011SWander Lairson Costa #[test]
test_function_invalid_return_value()22591e74d011SWander Lairson Costa fn test_function_invalid_return_value() {
22601e74d011SWander Lairson Costa let mut func = Function::new();
22611e74d011SWander Lairson Costa func.signature.returns.push(AbiParam::new(types::INVALID));
22621e74d011SWander Lairson Costa
22631e74d011SWander Lairson Costa let mut errors = VerifierErrors::default();
22641e74d011SWander Lairson Costa let flags = &settings::Flags::new(settings::builder());
22651e74d011SWander Lairson Costa let verifier = Verifier::new(&func, flags.into());
22661e74d011SWander Lairson Costa
22671e74d011SWander Lairson Costa let _ = verifier.typecheck_function_signature(&mut errors);
22681e74d011SWander Lairson Costa assert_err_with_msg!(errors, "Return value at position 0 has an invalid type");
22691e74d011SWander Lairson Costa }
2270838f2f46SAndrew Brown
2271838f2f46SAndrew Brown #[test]
test_printing_contextual_errors()2272838f2f46SAndrew Brown fn test_printing_contextual_errors() {
2273838f2f46SAndrew Brown // Build function.
2274838f2f46SAndrew Brown let mut func = Function::new();
2275832666c4SRyan Hunt let block0 = func.dfg.make_block();
2276832666c4SRyan Hunt func.layout.append_block(block0);
2277838f2f46SAndrew Brown
2278d02f895fSJamey Sharp // Build instruction "f64const 0.0" (missing one required result)
2279d02f895fSJamey Sharp let inst = func.dfg.make_inst(InstructionData::UnaryIeee64 {
2280d02f895fSJamey Sharp opcode: Opcode::F64const,
2281dc00bb61Sbeetrees imm: 0.0.into(),
2282838f2f46SAndrew Brown });
2283832666c4SRyan Hunt func.layout.append_inst(inst, block0);
2284838f2f46SAndrew Brown
2285838f2f46SAndrew Brown // Setup verifier.
2286838f2f46SAndrew Brown let mut errors = VerifierErrors::default();
2287838f2f46SAndrew Brown let flags = &settings::Flags::new(settings::builder());
2288838f2f46SAndrew Brown let verifier = Verifier::new(&func, flags.into());
2289838f2f46SAndrew Brown
2290838f2f46SAndrew Brown // Now the error message, when printed, should contain the instruction sequence causing the
2291d02f895fSJamey Sharp // error (i.e. f64const 0.0) and not only its entity value (i.e. inst0)
2292838f2f46SAndrew Brown let _ = verifier.typecheck_results(inst, types::I32, &mut errors);
2293838f2f46SAndrew Brown assert_eq!(
2294838f2f46SAndrew Brown format!("{}", errors.0[0]),
2295d02f895fSJamey Sharp "inst0 (f64const 0.0): has fewer result values than expected"
2296838f2f46SAndrew Brown )
2297838f2f46SAndrew Brown }
2298250ea0e5Sdata-pup
2299250ea0e5Sdata-pup #[test]
test_empty_block()2300832666c4SRyan Hunt fn test_empty_block() {
2301250ea0e5Sdata-pup let mut func = Function::new();
2302832666c4SRyan Hunt let block0 = func.dfg.make_block();
2303832666c4SRyan Hunt func.layout.append_block(block0);
2304250ea0e5Sdata-pup
2305250ea0e5Sdata-pup let flags = &settings::Flags::new(settings::builder());
2306250ea0e5Sdata-pup let verifier = Verifier::new(&func, flags.into());
2307250ea0e5Sdata-pup let mut errors = VerifierErrors::default();
2308250ea0e5Sdata-pup let _ = verifier.run(&mut errors);
2309250ea0e5Sdata-pup
2310832666c4SRyan Hunt assert_err_with_msg!(errors, "block0 cannot be empty");
2311250ea0e5Sdata-pup }
2312747ad3c4Slazypassion }
2313