diff --git a/cranelift/codegen/src/verifier/mod.rs b/cranelift/codegen/src/verifier/mod.rs index 1048248a28..30d14bb62d 100644 --- a/cranelift/codegen/src/verifier/mod.rs +++ b/cranelift/codegen/src/verifier/mod.rs @@ -61,9 +61,9 @@ use crate::dbg::DisplayList; use crate::dominator_tree::DominatorTree; use crate::entity::SparseSet; use crate::flowgraph::{BlockPredecessor, ControlFlowGraph}; -use crate::ir; use crate::ir::entities::AnyEntity; use crate::ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint}; +use crate::ir::{self, ArgumentExtension}; use crate::ir::{ types, ArgumentPurpose, Block, Constant, DynamicStackSlot, FuncRef, Function, GlobalValue, Inst, JumpTable, MemFlags, Opcode, SigRef, StackSlot, Type, Value, ValueDef, ValueList, @@ -1648,45 +1648,57 @@ impl<'a> Verifier<'a> { } fn typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> { - self.func + let params = self + .func .signature .params .iter() .enumerate() - .filter(|(_, ¶m)| param.value_type == types::INVALID) - .for_each(|(i, _)| { + .map(|p| (true, p)); + let returns = self + .func + .signature + .returns + .iter() + .enumerate() + .map(|p| (false, p)); + + for (is_argument, (i, param)) in params.chain(returns) { + let is_return = !is_argument; + let item = if is_argument { + "Parameter" + } else { + "Return value" + }; + + if param.value_type == types::INVALID { errors.report(( AnyEntity::Function, - format!("Parameter at position {} has an invalid type", i), + format!("{item} at position {i} has an invalid type"), )); - }); + } - self.func - .signature - .returns - .iter() - .enumerate() - .filter(|(_, &ret)| ret.value_type == types::INVALID) - .for_each(|(i, _)| { - errors.report(( - AnyEntity::Function, - format!("Return value at position {} has an invalid type", i), - )) - }); - - self.func - .signature - .returns - .iter() - .enumerate() - .for_each(|(i, ret)| { - if let ArgumentPurpose::StructArgument(_) = ret.purpose { + if let ArgumentPurpose::StructArgument(_) = param.purpose { + if is_return { errors.report(( AnyEntity::Function, - format!("Return value at position {} can't be an struct argument", i), + format!("{item} at position {i} can't be an struct argument"), )) } - }); + } + + let ty_allows_extension = param.value_type.is_int(); + let has_extension = param.extension != ArgumentExtension::None; + if !ty_allows_extension && has_extension { + errors.report(( + AnyEntity::Function, + format!( + "{} at position {} has invalid extension {:?}", + item, i, param.extension + ), + )); + } + } if errors.has_error() { Err(()) diff --git a/cranelift/filetests/filetests/verifier/argument-extension.clif b/cranelift/filetests/filetests/verifier/argument-extension.clif new file mode 100644 index 0000000000..198a758f82 --- /dev/null +++ b/cranelift/filetests/filetests/verifier/argument-extension.clif @@ -0,0 +1,26 @@ +test verifier + +function %float_with_sext(f32 sext) -> f32 { ; error: Parameter at position 0 has invalid extension Sext +block0(v0: f32): + return v0 +} + +function %float_with_uext(f32 uext) -> f32 { ; error: Parameter at position 0 has invalid extension Uext +block0(v0: f32): + return v0 +} + +function %float_ret_with_sext(f32) -> f32 sext { ; error: Return value at position 0 has invalid extension Sext +block0(v0: f32): + return v0 +} + +function %float_ret_with_uext(f32) -> f32 uext { ; error: Return value at position 0 has invalid extension Uext +block0(v0: f32): + return v0 +} + +function %simd_ext(i32x4 sext) -> i32x4 { ; error: Parameter at position 0 has invalid extension Sext +block0(v0: i32x4): + return v0 +} diff --git a/cranelift/fuzzgen/src/function_generator.rs b/cranelift/fuzzgen/src/function_generator.rs index 2888cbca97..d5b51c5c59 100644 --- a/cranelift/fuzzgen/src/function_generator.rs +++ b/cranelift/fuzzgen/src/function_generator.rs @@ -1230,10 +1230,14 @@ where let value_type = self.generate_type()?; // TODO: There are more argument purposes to be explored... let purpose = ArgumentPurpose::Normal; - let extension = match self.u.int_in_range(0..=2)? { - 2 => ArgumentExtension::Sext, - 1 => ArgumentExtension::Uext, - _ => ArgumentExtension::None, + let extension = if value_type.is_int() { + *self.u.choose(&[ + ArgumentExtension::Sext, + ArgumentExtension::Uext, + ArgumentExtension::None, + ])? + } else { + ArgumentExtension::None }; Ok(AbiParam {