1c227063fSAndrew Brown //! Generate Cranelift compiler settings. 2c227063fSAndrew Brown 3*9b896d2aSAlex Crichton use crate::generators::ModuleConfig; 4c227063fSAndrew Brown use arbitrary::{Arbitrary, Unstructured}; 5*9b896d2aSAlex Crichton use std::collections::HashMap; 6c227063fSAndrew Brown 7c227063fSAndrew Brown /// Choose between matching the host architecture or a cross-compilation target. 8c227063fSAndrew Brown #[derive(Clone, Debug, Eq, Hash, PartialEq)] 9c227063fSAndrew Brown pub enum CodegenSettings { 10c227063fSAndrew Brown /// Use the host's feature set. 11c227063fSAndrew Brown Native, 12c227063fSAndrew Brown /// Generate a modified flag set for the current host. 13c227063fSAndrew Brown #[allow(dead_code)] 14c227063fSAndrew Brown Target { 15c227063fSAndrew Brown /// The target triple of the host. 16c227063fSAndrew Brown target: String, 17c227063fSAndrew Brown /// A list of CPU features to enable, e.g., `("has_avx", "false")`. 18c227063fSAndrew Brown flags: Vec<(String, String)>, 19c227063fSAndrew Brown }, 20c227063fSAndrew Brown } 21c227063fSAndrew Brown 22c227063fSAndrew Brown impl CodegenSettings { 23c227063fSAndrew Brown /// Configure Wasmtime with these codegen settings. 24c227063fSAndrew Brown pub fn configure(&self, config: &mut wasmtime::Config) { 25c227063fSAndrew Brown match self { 26c227063fSAndrew Brown CodegenSettings::Native => {} 27c227063fSAndrew Brown CodegenSettings::Target { target, flags } => { 28c227063fSAndrew Brown config.target(target).unwrap(); 29c227063fSAndrew Brown for (key, value) in flags { 30c227063fSAndrew Brown unsafe { 31c227063fSAndrew Brown config.cranelift_flag_set(key, value); 32c227063fSAndrew Brown } 33c227063fSAndrew Brown } 34c227063fSAndrew Brown } 35c227063fSAndrew Brown } 36c227063fSAndrew Brown } 37*9b896d2aSAlex Crichton 38*9b896d2aSAlex Crichton /// Features such as sse4.2 are unconditionally enabled on the x86_64 target 39*9b896d2aSAlex Crichton /// because they are hard required for SIMD, but when SIMD is disabled, for 40*9b896d2aSAlex Crichton /// example, we support disabling these features. 41*9b896d2aSAlex Crichton /// 42*9b896d2aSAlex Crichton /// This method will take the wasm feature selection chosen, through 43*9b896d2aSAlex Crichton /// `module_config`, and possibly try to disable some more features by 44*9b896d2aSAlex Crichton /// reading more of the input. 45*9b896d2aSAlex Crichton pub fn maybe_disable_more_features( 46*9b896d2aSAlex Crichton &mut self, 47*9b896d2aSAlex Crichton module_config: &ModuleConfig, 48*9b896d2aSAlex Crichton u: &mut Unstructured<'_>, 49*9b896d2aSAlex Crichton ) -> arbitrary::Result<()> { 50*9b896d2aSAlex Crichton let flags = match self { 51*9b896d2aSAlex Crichton CodegenSettings::Target { flags, .. } => flags, 52*9b896d2aSAlex Crichton _ => return Ok(()), 53*9b896d2aSAlex Crichton }; 54*9b896d2aSAlex Crichton 55*9b896d2aSAlex Crichton if !module_config.config.simd_enabled { 56*9b896d2aSAlex Crichton // Note that regardless of architecture these booleans are generated 57*9b896d2aSAlex Crichton // to have test case failures unrelated to codegen setting input 58*9b896d2aSAlex Crichton // that fail on one architecture to fail on other architectures as 59*9b896d2aSAlex Crichton // well. 60*9b896d2aSAlex Crichton let new_flags = ["has_sse3", "has_ssse3", "has_sse41", "has_sse42"] 61*9b896d2aSAlex Crichton .into_iter() 62*9b896d2aSAlex Crichton .map(|name| Ok((name, u.arbitrary()?))) 63*9b896d2aSAlex Crichton .collect::<arbitrary::Result<HashMap<_, bool>>>()?; 64*9b896d2aSAlex Crichton 65*9b896d2aSAlex Crichton for (name, val) in flags { 66*9b896d2aSAlex Crichton if let Some(new_value) = new_flags.get(name.as_str()) { 67*9b896d2aSAlex Crichton *val = new_value.to_string(); 68*9b896d2aSAlex Crichton } 69*9b896d2aSAlex Crichton } 70*9b896d2aSAlex Crichton } 71*9b896d2aSAlex Crichton Ok(()) 72*9b896d2aSAlex Crichton } 73c227063fSAndrew Brown } 74c227063fSAndrew Brown 75c227063fSAndrew Brown impl<'a> Arbitrary<'a> for CodegenSettings { 76c227063fSAndrew Brown #[allow(unused_macros, unused_variables)] 77c227063fSAndrew Brown fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { 78c227063fSAndrew Brown // Helper macro to enable clif features based on what the native host 79c227063fSAndrew Brown // supports. If the input says to enable a feature and the host doesn't 80c227063fSAndrew Brown // support it then that test case is rejected with a warning. 81c227063fSAndrew Brown // 82c227063fSAndrew Brown // Note that this specifically consumes bytes from the fuzz input for 83c227063fSAndrew Brown // features for all targets, discarding anything which isn't applicable 84c227063fSAndrew Brown // to the current target. The theory behind this is that most fuzz bugs 85c227063fSAndrew Brown // won't be related to this feature selection so by consistently 86c227063fSAndrew Brown // consuming input irrespective of the current platform reproducing fuzz 87c227063fSAndrew Brown // bugs should be easier between different architectures. 88c227063fSAndrew Brown macro_rules! target_features { 89c227063fSAndrew Brown ( 90c227063fSAndrew Brown $( 91c227063fSAndrew Brown $arch:tt => { 92c227063fSAndrew Brown test:$test:ident, 93c227063fSAndrew Brown $(std: $std:tt => clif: $clif:tt $(ratio: $a:tt in $b:tt)?,)* 94c227063fSAndrew Brown }, 95c227063fSAndrew Brown )* 96c227063fSAndrew Brown ) => ({ 97c227063fSAndrew Brown let mut flags = Vec::new(); 98c227063fSAndrew Brown $( // for each `$arch` 99c227063fSAndrew Brown $( // for each `$std`/`$clif` pair 100c227063fSAndrew Brown // Use the input to generate whether `$clif` will be 101c227063fSAndrew Brown // enabled. By default this is a 1 in 2 chance but each 102c227063fSAndrew Brown // feature supports a custom ratio as well which shadows 103c227063fSAndrew Brown // the (low, hi) 104c227063fSAndrew Brown let (low, hi) = (1, 2); 105c227063fSAndrew Brown $(let (low, hi) = ($a, $b);)? 106c227063fSAndrew Brown let enable = u.ratio(low, hi)?; 107c227063fSAndrew Brown 108c227063fSAndrew Brown // If we're actually on the relevant platform and the 109c227063fSAndrew Brown // feature is enabled be sure to check that this host 110c227063fSAndrew Brown // supports it. If the host doesn't support it then 111c227063fSAndrew Brown // print a warning and return an error because this fuzz 112c227063fSAndrew Brown // input must be discarded. 113c227063fSAndrew Brown #[cfg(target_arch = $arch)] 114c227063fSAndrew Brown if enable && !std::arch::$test!($std) { 115c227063fSAndrew Brown log::warn!("want to enable clif `{}` but host doesn't support it", 116c227063fSAndrew Brown $clif); 117c227063fSAndrew Brown return Err(arbitrary::Error::EmptyChoose) 118c227063fSAndrew Brown } 119c227063fSAndrew Brown 120c227063fSAndrew Brown // And finally actually push the feature into the set of 121c227063fSAndrew Brown // flags to enable, but only if we're on the right 122c227063fSAndrew Brown // architecture. 123c227063fSAndrew Brown if cfg!(target_arch = $arch) { 124c227063fSAndrew Brown flags.push(( 125c227063fSAndrew Brown $clif.to_string(), 126c227063fSAndrew Brown enable.to_string(), 127c227063fSAndrew Brown )); 128c227063fSAndrew Brown } 129c227063fSAndrew Brown )* 130c227063fSAndrew Brown )* 131c227063fSAndrew Brown flags 132c227063fSAndrew Brown }) 133c227063fSAndrew Brown } 134c227063fSAndrew Brown if u.ratio(1, 10)? { 135c227063fSAndrew Brown let flags = target_features! { 136c227063fSAndrew Brown "x86_64" => { 137c227063fSAndrew Brown test: is_x86_feature_detected, 138c227063fSAndrew Brown 139c227063fSAndrew Brown // These features are considered to be baseline required by 140c227063fSAndrew Brown // Wasmtime. Currently some SIMD code generation will 141c227063fSAndrew Brown // fail if these features are disabled, so unconditionally 142c227063fSAndrew Brown // enable them as we're not interested in fuzzing without 143c227063fSAndrew Brown // them. 144*9b896d2aSAlex Crichton // 145*9b896d2aSAlex Crichton // Note that these may still be disabled above in 146*9b896d2aSAlex Crichton // `maybe_disable_more_features`. 147c227063fSAndrew Brown std:"sse3" => clif:"has_sse3" ratio: 1 in 1, 148c227063fSAndrew Brown std:"ssse3" => clif:"has_ssse3" ratio: 1 in 1, 149c227063fSAndrew Brown std:"sse4.1" => clif:"has_sse41" ratio: 1 in 1, 150c227063fSAndrew Brown std:"sse4.2" => clif:"has_sse42" ratio: 1 in 1, 151c227063fSAndrew Brown 152c227063fSAndrew Brown std:"popcnt" => clif:"has_popcnt", 153c227063fSAndrew Brown std:"avx" => clif:"has_avx", 154c227063fSAndrew Brown std:"avx2" => clif:"has_avx2", 15502c3b47dSAfonso Bordado std:"fma" => clif:"has_fma", 156c227063fSAndrew Brown std:"bmi1" => clif:"has_bmi1", 157c227063fSAndrew Brown std:"bmi2" => clif:"has_bmi2", 158c227063fSAndrew Brown std:"lzcnt" => clif:"has_lzcnt", 159c227063fSAndrew Brown 160c227063fSAndrew Brown // not a lot of of cpus support avx512 so these are weighted 161c227063fSAndrew Brown // to get enabled much less frequently. 162c227063fSAndrew Brown std:"avx512bitalg" => clif:"has_avx512bitalg" ratio:1 in 1000, 163c227063fSAndrew Brown std:"avx512dq" => clif:"has_avx512dq" ratio: 1 in 1000, 164c227063fSAndrew Brown std:"avx512f" => clif:"has_avx512f" ratio: 1 in 1000, 165c227063fSAndrew Brown std:"avx512vl" => clif:"has_avx512vl" ratio: 1 in 1000, 166c227063fSAndrew Brown std:"avx512vbmi" => clif:"has_avx512vbmi" ratio: 1 in 1000, 167c227063fSAndrew Brown }, 168c227063fSAndrew Brown "aarch64" => { 169c227063fSAndrew Brown test: is_aarch64_feature_detected, 170c227063fSAndrew Brown 171d8b29089SAnton Kirilov std: "bti" => clif: "use_bti", 172c227063fSAndrew Brown std: "lse" => clif: "has_lse", 1731481721cSAnton Kirilov // even though the natural correspondence seems to be 1741481721cSAnton Kirilov // between "paca" and "has_pauth", the latter has no effect 1751481721cSAnton Kirilov // in isolation, so we actually use the setting that affects 1761481721cSAnton Kirilov // code generation 1771481721cSAnton Kirilov std: "paca" => clif: "sign_return_address", 1781481721cSAnton Kirilov // "paca" and "pacg" check for the same underlying 1791481721cSAnton Kirilov // architectural feature, so we use the latter to cover more 1801481721cSAnton Kirilov // code generation settings, of which we have chosen the one 1811481721cSAnton Kirilov // with the most significant effect 1821481721cSAnton Kirilov std: "pacg" => clif: "sign_return_address_all" ratio: 1 in 2, 183c227063fSAndrew Brown }, 184c227063fSAndrew Brown }; 185c227063fSAndrew Brown return Ok(CodegenSettings::Target { 186c227063fSAndrew Brown target: target_lexicon::Triple::host().to_string(), 187c227063fSAndrew Brown flags, 188c227063fSAndrew Brown }); 189c227063fSAndrew Brown } 190c227063fSAndrew Brown Ok(CodegenSettings::Native) 191c227063fSAndrew Brown } 192c227063fSAndrew Brown } 193