From f10d665bb9cacceee6051989e99c0934c542ad84 Mon Sep 17 00:00:00 2001 From: Afonso Bordado Date: Sat, 2 Sep 2023 04:00:50 +0100 Subject: [PATCH] fuzzgen: Enable SIMD fuzzing for RISC-V (#6949) --- cranelift/fuzzgen/src/cranelift_arbitrary.rs | 47 +++++++++----------- cranelift/fuzzgen/src/function_generator.rs | 21 +++++---- cranelift/fuzzgen/src/lib.rs | 15 +++++-- cranelift/fuzzgen/src/target_isa_extras.rs | 21 +++++++++ fuzz/fuzz_targets/cranelift-icache.rs | 2 +- 5 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 cranelift/fuzzgen/src/target_isa_extras.rs diff --git a/cranelift/fuzzgen/src/cranelift_arbitrary.rs b/cranelift/fuzzgen/src/cranelift_arbitrary.rs index 76cc6ebb1952..9de4d162c7b9 100644 --- a/cranelift/fuzzgen/src/cranelift_arbitrary.rs +++ b/cranelift/fuzzgen/src/cranelift_arbitrary.rs @@ -11,11 +11,12 @@ use target_lexicon::Architecture; /// A trait for generating random Cranelift datastructures. pub trait CraneliftArbitrary { - fn _type(&mut self, architecture: Architecture) -> Result; + fn _type(&mut self, simd_enabled: bool) -> Result; fn callconv(&mut self, architecture: Architecture) -> Result; - fn abi_param(&mut self, architecture: Architecture) -> Result; + fn abi_param(&mut self, simd_enabled: bool) -> Result; fn signature( &mut self, + simd_enabled: bool, architecture: Architecture, max_params: usize, max_rets: usize, @@ -23,26 +24,21 @@ pub trait CraneliftArbitrary { fn datavalue(&mut self, ty: Type) -> Result; } -/// Returns the set of types that are valid for value generation, dependent on architecture. -pub fn types_for_architecture(architecture: Architecture) -> &'static [Type] { - // TODO: It would be nice if we could get these directly from cranelift - // TODO: RISCV does not support SIMD yet - let supports_simd = !matches!(architecture, Architecture::Riscv64(_)); - 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] - } -} - impl<'a> CraneliftArbitrary for &mut Unstructured<'a> { - fn _type(&mut self, architecture: Architecture) -> Result { - Ok(*self.choose(types_for_architecture(architecture))?) + fn _type(&mut self, simd_enabled: bool) -> Result { + // TODO: It would be nice if we could get these directly from cranelift + let choices: &[Type] = if simd_enabled { + &[ + 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] + }; + + Ok(*self.choose(choices)?) } fn callconv(&mut self, architecture: Architecture) -> Result { @@ -71,8 +67,8 @@ impl<'a> CraneliftArbitrary for &mut Unstructured<'a> { Ok(*self.choose(&allowed_callconvs[..])?) } - fn abi_param(&mut self, architecture: Architecture) -> Result { - let value_type = self._type(architecture)?; + fn abi_param(&mut self, simd_enabled: bool) -> Result { + let value_type = self._type(simd_enabled)?; // TODO: There are more argument purposes to be explored... let purpose = ArgumentPurpose::Normal; let extension = if value_type.is_int() { @@ -94,6 +90,7 @@ impl<'a> CraneliftArbitrary for &mut Unstructured<'a> { fn signature( &mut self, + simd_enabled: bool, architecture: Architecture, max_params: usize, max_rets: usize, @@ -102,11 +99,11 @@ impl<'a> CraneliftArbitrary for &mut Unstructured<'a> { let mut sig = Signature::new(callconv); for _ in 0..max_params { - sig.params.push(self.abi_param(architecture)?); + sig.params.push(self.abi_param(simd_enabled)?); } for _ in 0..max_rets { - sig.returns.push(self.abi_param(architecture)?); + sig.returns.push(self.abi_param(simd_enabled)?); } Ok(sig) diff --git a/cranelift/fuzzgen/src/function_generator.rs b/cranelift/fuzzgen/src/function_generator.rs index 216adce67662..b2ce4e1ee189 100644 --- a/cranelift/fuzzgen/src/function_generator.rs +++ b/cranelift/fuzzgen/src/function_generator.rs @@ -1,5 +1,6 @@ use crate::config::Config; use crate::cranelift_arbitrary::CraneliftArbitrary; +use crate::target_isa_extras::TargetIsaExtras; use anyhow::Result; use arbitrary::{Arbitrary, Unstructured}; use cranelift::codegen::data_value::DataValue; @@ -717,12 +718,6 @@ 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!( op, args, @@ -761,9 +756,17 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) - (Opcode::Bitcast, &[I128], &[_]), (Opcode::Bitcast, &[_], &[I128]), // TODO - (Opcode::SelectSpectreGuard, &[_, _, _], &[F32 | F64]), + ( + Opcode::SelectSpectreGuard, + &[_, _, _], + &[F32 | F64 | I8X16 | I16X8 | I32X4 | I64X2 | F64X2 | F32X4] + ), // TODO (Opcode::Bitselect, &[_, _, _], &[F32 | F64]), + ( + Opcode::Rotr | Opcode::Rotl, + &[I8X16 | I16X8 | I32X4 | I64X2, _] + ), ) } @@ -1823,7 +1826,7 @@ where let mut params = Vec::with_capacity(param_count); for _ in 0..param_count { - params.push(self.u._type(self.isa.triple().architecture)?); + params.push(self.u._type((&*self.isa).supports_simd())?); } Ok(params) } @@ -1843,7 +1846,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(self.isa.triple().architecture)?; + let ty = self.u._type((&*self.isa).supports_simd())?; let value = self.generate_const(builder, ty)?; vars.push((ty, value)); } diff --git a/cranelift/fuzzgen/src/lib.rs b/cranelift/fuzzgen/src/lib.rs index 57f3bfe3f030..d71658182492 100644 --- a/cranelift/fuzzgen/src/lib.rs +++ b/cranelift/fuzzgen/src/lib.rs @@ -8,11 +8,12 @@ use cranelift::codegen::ir::{types::*, UserExternalName, UserFuncName}; use cranelift::codegen::ir::{Function, LibCall}; use cranelift::codegen::isa::{self, Builder}; use cranelift::codegen::Context; -use cranelift::prelude::isa::OwnedTargetIsa; +use cranelift::prelude::isa::{OwnedTargetIsa, TargetIsa}; use cranelift::prelude::settings::SettingKind; use cranelift::prelude::*; use cranelift_arbitrary::CraneliftArbitrary; use cranelift_native::builder_with_options; +use target_isa_extras::TargetIsaExtras; use target_lexicon::Architecture; mod config; @@ -20,6 +21,7 @@ mod cranelift_arbitrary; mod function_generator; mod passes; mod print; +mod target_isa_extras; pub use print::PrintableTestCase; @@ -53,10 +55,15 @@ where } } - pub fn generate_signature(&mut self, architecture: Architecture) -> Result { + pub fn generate_signature(&mut self, isa: &dyn TargetIsa) -> Result { 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())?; - Ok(self.u.signature(architecture, max_params, max_rets)?) + Ok(self.u.signature( + isa.supports_simd(), + isa.triple().architecture, + max_params, + max_rets, + )?) } pub fn generate_test_inputs(mut self, signature: &Signature) -> Result> { @@ -144,7 +151,7 @@ where usercalls: Vec<(UserExternalName, Signature)>, libcalls: Vec, ) -> Result { - let sig = self.generate_signature(isa.triple().architecture)?; + let sig = self.generate_signature(&*isa)?; let func = FunctionGenerator::new( &mut self.u, diff --git a/cranelift/fuzzgen/src/target_isa_extras.rs b/cranelift/fuzzgen/src/target_isa_extras.rs new file mode 100644 index 000000000000..6c3bd249e22a --- /dev/null +++ b/cranelift/fuzzgen/src/target_isa_extras.rs @@ -0,0 +1,21 @@ +use cranelift::prelude::isa::TargetIsa; +use target_lexicon::Architecture; + +pub trait TargetIsaExtras { + fn supports_simd(&self) -> bool; +} + +impl TargetIsaExtras for &dyn TargetIsa { + fn supports_simd(&self) -> bool { + match self.triple().architecture { + // RISC-V only supports SIMD with the V extension. + Architecture::Riscv64(_) => self + .isa_flags() + .iter() + .find(|f| f.name == "has_v") + .and_then(|f| f.as_bool()) + .unwrap_or(false), + _ => true, + } + } +} diff --git a/fuzz/fuzz_targets/cranelift-icache.rs b/fuzz/fuzz_targets/cranelift-icache.rs index eb0afff42ea5..b288cf8ebb59 100644 --- a/fuzz/fuzz_targets/cranelift-icache.rs +++ b/fuzz/fuzz_targets/cranelift-icache.rs @@ -69,7 +69,7 @@ impl FunctionWithIsa { let usercalls = (0..func_count) .map(|i| { let name = UserExternalName::new(2, i as u32); - let sig = gen.generate_signature(architecture)?; + let sig = gen.generate_signature(&*isa)?; Ok((name, sig)) }) .collect::>>()