fuzzgen: Initial SIMD support (#5885)
* fuzzgen: Initial SIMD support * riscv64: Address PR Feedback Thanks!
This commit is contained in:
@@ -7,27 +7,39 @@ use cranelift::codegen::isa::CallConv;
|
||||
|
||||
use arbitrary::Unstructured;
|
||||
use cranelift::prelude::{Ieee32, Ieee64};
|
||||
use target_lexicon::Architecture;
|
||||
|
||||
/// A trait for generating random Cranelift datastructures.
|
||||
pub trait CraneliftArbitrary {
|
||||
fn _type(&mut self) -> Result<Type>;
|
||||
fn _type(&mut self, architecture: Architecture) -> Result<Type>;
|
||||
fn callconv(&mut self) -> Result<CallConv>;
|
||||
fn abi_param(&mut self) -> Result<AbiParam>;
|
||||
fn signature(&mut self, max_params: usize, max_rets: usize) -> Result<Signature>;
|
||||
fn abi_param(&mut self, architecture: Architecture) -> Result<AbiParam>;
|
||||
fn signature(
|
||||
&mut self,
|
||||
architecture: Architecture,
|
||||
max_params: usize,
|
||||
max_rets: usize,
|
||||
) -> Result<Signature>;
|
||||
fn datavalue(&mut self, ty: Type) -> Result<DataValue>;
|
||||
}
|
||||
|
||||
impl<'a> CraneliftArbitrary for &mut Unstructured<'a> {
|
||||
fn _type(&mut self) -> Result<Type> {
|
||||
fn _type(&mut self, architecture: Architecture) -> Result<Type> {
|
||||
// TODO: It would be nice if we could get these directly from cranelift
|
||||
let scalars = [
|
||||
I8, I16, I32, I64, I128, F32, F64,
|
||||
// R32, R64,
|
||||
];
|
||||
// TODO: vector types
|
||||
// TODO: RISCV does not support SIMD yet
|
||||
let supports_simd = !matches!(architecture, Architecture::Riscv64(_));
|
||||
let choices = if supports_simd {
|
||||
&[
|
||||
I8, I16, I32, I64, I128, // Scalar Integers
|
||||
F32, F64, // Scalar Floats
|
||||
I8X16, I16X8, I32X4, I64X2, // SIMD Integers
|
||||
F32X4, F64X2, // SIMD Floats
|
||||
][..]
|
||||
} else {
|
||||
&[I8, I16, I32, I64, I128, F32, F64][..]
|
||||
};
|
||||
|
||||
let ty = self.choose(&scalars[..])?;
|
||||
Ok(*ty)
|
||||
Ok(*self.choose(choices)?)
|
||||
}
|
||||
|
||||
fn callconv(&mut self) -> Result<CallConv> {
|
||||
@@ -35,8 +47,8 @@ impl<'a> CraneliftArbitrary for &mut Unstructured<'a> {
|
||||
Ok(CallConv::SystemV)
|
||||
}
|
||||
|
||||
fn abi_param(&mut self) -> Result<AbiParam> {
|
||||
let value_type = self._type()?;
|
||||
fn abi_param(&mut self, architecture: Architecture) -> Result<AbiParam> {
|
||||
let value_type = self._type(architecture)?;
|
||||
// TODO: There are more argument purposes to be explored...
|
||||
let purpose = ArgumentPurpose::Normal;
|
||||
let extension = if value_type.is_int() {
|
||||
@@ -56,16 +68,21 @@ impl<'a> CraneliftArbitrary for &mut Unstructured<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn signature(&mut self, max_params: usize, max_rets: usize) -> Result<Signature> {
|
||||
fn signature(
|
||||
&mut self,
|
||||
architecture: Architecture,
|
||||
max_params: usize,
|
||||
max_rets: usize,
|
||||
) -> Result<Signature> {
|
||||
let callconv = self.callconv()?;
|
||||
let mut sig = Signature::new(callconv);
|
||||
|
||||
for _ in 0..max_params {
|
||||
sig.params.push(self.abi_param()?);
|
||||
sig.params.push(self.abi_param(architecture)?);
|
||||
}
|
||||
|
||||
for _ in 0..max_rets {
|
||||
sig.returns.push(self.abi_param()?);
|
||||
sig.returns.push(self.abi_param(architecture)?);
|
||||
}
|
||||
|
||||
Ok(sig)
|
||||
@@ -88,6 +105,9 @@ impl<'a> CraneliftArbitrary for &mut Unstructured<'a> {
|
||||
// such as Signaling NaN's / NaN's with payload, so generate floats from integers.
|
||||
F32 => DataValue::F32(Ieee32::with_bits(self.arbitrary::<u32>()?)),
|
||||
F64 => DataValue::F64(Ieee64::with_bits(self.arbitrary::<u64>()?)),
|
||||
ty if ty.is_vector() && ty.bits() == 128 => {
|
||||
DataValue::V128(self.arbitrary::<[u8; 16]>()?)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -565,6 +565,12 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
|
||||
}
|
||||
|
||||
Architecture::Riscv64(_) => {
|
||||
// RISC-V Does not support SIMD at all
|
||||
let is_simd = args.iter().chain(rets).any(|t| t.is_vector());
|
||||
if is_simd {
|
||||
return false;
|
||||
}
|
||||
|
||||
exceptions!(
|
||||
// TODO
|
||||
(Opcode::IaddCout),
|
||||
@@ -737,6 +743,10 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
|
||||
(Opcode::Iabs, &[I32], &[I32], insert_opcode),
|
||||
(Opcode::Iabs, &[I64], &[I64], insert_opcode),
|
||||
(Opcode::Iabs, &[I128], &[I128], insert_opcode),
|
||||
(Opcode::Iabs, &[I8X16, I8X16], &[I8X16], insert_opcode),
|
||||
(Opcode::Iabs, &[I16X8, I16X8], &[I16X8], insert_opcode),
|
||||
(Opcode::Iabs, &[I32X4, I32X4], &[I32X4], insert_opcode),
|
||||
(Opcode::Iabs, &[I64X2, I64X2], &[I64X2], insert_opcode),
|
||||
// Smin
|
||||
(Opcode::Smin, &[I8, I8], &[I8], insert_opcode),
|
||||
(Opcode::Smin, &[I16, I16], &[I16], insert_opcode),
|
||||
@@ -1552,6 +1562,11 @@ where
|
||||
}
|
||||
DataValue::F32(f) => builder.ins().f32const(f),
|
||||
DataValue::F64(f) => builder.ins().f64const(f),
|
||||
DataValue::V128(bytes) => {
|
||||
let data = bytes.to_vec().into();
|
||||
let handle = builder.func.dfg.constants.insert(data);
|
||||
builder.ins().vconst(ty, handle)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
})
|
||||
}
|
||||
@@ -1922,7 +1937,7 @@ where
|
||||
|
||||
let mut params = Vec::with_capacity(param_count);
|
||||
for _ in 0..param_count {
|
||||
params.push(self.u._type()?);
|
||||
params.push(self.u._type(self.target_triple.architecture)?);
|
||||
}
|
||||
Ok(params)
|
||||
}
|
||||
@@ -1942,7 +1957,7 @@ where
|
||||
|
||||
// Create a pool of vars that are going to be used in this function
|
||||
for _ in 0..self.param(&self.config.vars_per_function)? {
|
||||
let ty = self.u._type()?;
|
||||
let ty = self.u._type(self.target_triple.architecture)?;
|
||||
let value = self.generate_const(builder, ty)?;
|
||||
vars.push((ty, value));
|
||||
}
|
||||
|
||||
@@ -256,7 +256,9 @@ where
|
||||
fn generate_func(&mut self, target_triple: Triple) -> Result<Function> {
|
||||
let max_params = self.u.int_in_range(self.config.signature_params.clone())?;
|
||||
let max_rets = self.u.int_in_range(self.config.signature_rets.clone())?;
|
||||
let sig = self.u.signature(max_params, max_rets)?;
|
||||
let sig = self
|
||||
.u
|
||||
.signature(target_triple.architecture, max_params, max_rets)?;
|
||||
|
||||
// Function name must be in a different namespace than TESTFILE_NAMESPACE (0)
|
||||
let fname = UserFuncName::user(1, 0);
|
||||
@@ -266,7 +268,9 @@ where
|
||||
.map(|i| {
|
||||
let max_params = self.u.int_in_range(self.config.signature_params.clone())?;
|
||||
let max_rets = self.u.int_in_range(self.config.signature_rets.clone())?;
|
||||
let sig = self.u.signature(max_params, max_rets)?;
|
||||
let sig = self
|
||||
.u
|
||||
.signature(target_triple.architecture, max_params, max_rets)?;
|
||||
let name = UserExternalName {
|
||||
namespace: 2,
|
||||
index: i as u32,
|
||||
|
||||
Reference in New Issue
Block a user