cranelift: Forbid argument extensions for floats and SIMD vectors (#5536)
* fuzzgen: Generate argument extensions only for integer argumetns * cranelift: Add verifier check for argument extensions
This commit is contained in:
@@ -61,9 +61,9 @@ use crate::dbg::DisplayList;
|
|||||||
use crate::dominator_tree::DominatorTree;
|
use crate::dominator_tree::DominatorTree;
|
||||||
use crate::entity::SparseSet;
|
use crate::entity::SparseSet;
|
||||||
use crate::flowgraph::{BlockPredecessor, ControlFlowGraph};
|
use crate::flowgraph::{BlockPredecessor, ControlFlowGraph};
|
||||||
use crate::ir;
|
|
||||||
use crate::ir::entities::AnyEntity;
|
use crate::ir::entities::AnyEntity;
|
||||||
use crate::ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint};
|
use crate::ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint};
|
||||||
|
use crate::ir::{self, ArgumentExtension};
|
||||||
use crate::ir::{
|
use crate::ir::{
|
||||||
types, ArgumentPurpose, Block, Constant, DynamicStackSlot, FuncRef, Function, GlobalValue,
|
types, ArgumentPurpose, Block, Constant, DynamicStackSlot, FuncRef, Function, GlobalValue,
|
||||||
Inst, JumpTable, MemFlags, Opcode, SigRef, StackSlot, Type, Value, ValueDef, ValueList,
|
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<()> {
|
fn typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
|
||||||
self.func
|
let params = self
|
||||||
|
.func
|
||||||
.signature
|
.signature
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|(_, ¶m)| param.value_type == types::INVALID)
|
.map(|p| (true, p));
|
||||||
.for_each(|(i, _)| {
|
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((
|
errors.report((
|
||||||
AnyEntity::Function,
|
AnyEntity::Function,
|
||||||
format!("Parameter at position {} has an invalid type", i),
|
format!("{item} at position {i} has an invalid type"),
|
||||||
));
|
));
|
||||||
});
|
}
|
||||||
|
|
||||||
self.func
|
if let ArgumentPurpose::StructArgument(_) = param.purpose {
|
||||||
.signature
|
if is_return {
|
||||||
.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 {
|
|
||||||
errors.report((
|
errors.report((
|
||||||
AnyEntity::Function,
|
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() {
|
if errors.has_error() {
|
||||||
Err(())
|
Err(())
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -1230,10 +1230,14 @@ where
|
|||||||
let value_type = self.generate_type()?;
|
let value_type = self.generate_type()?;
|
||||||
// TODO: There are more argument purposes to be explored...
|
// TODO: There are more argument purposes to be explored...
|
||||||
let purpose = ArgumentPurpose::Normal;
|
let purpose = ArgumentPurpose::Normal;
|
||||||
let extension = match self.u.int_in_range(0..=2)? {
|
let extension = if value_type.is_int() {
|
||||||
2 => ArgumentExtension::Sext,
|
*self.u.choose(&[
|
||||||
1 => ArgumentExtension::Uext,
|
ArgumentExtension::Sext,
|
||||||
_ => ArgumentExtension::None,
|
ArgumentExtension::Uext,
|
||||||
|
ArgumentExtension::None,
|
||||||
|
])?
|
||||||
|
} else {
|
||||||
|
ArgumentExtension::None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(AbiParam {
|
Ok(AbiParam {
|
||||||
|
|||||||
Reference in New Issue
Block a user