1c227063fSAndrew Brown //! Generate Cranelift compiler settings. 2c227063fSAndrew Brown 3c227063fSAndrew Brown use arbitrary::{Arbitrary, Unstructured}; 4c227063fSAndrew Brown 5c227063fSAndrew Brown /// Choose between matching the host architecture or a cross-compilation target. 6c227063fSAndrew Brown #[derive(Clone, Debug, Eq, Hash, PartialEq)] 7c227063fSAndrew Brown pub enum CodegenSettings { 8c227063fSAndrew Brown /// Use the host's feature set. 9c227063fSAndrew Brown Native, 10c227063fSAndrew Brown /// Generate a modified flag set for the current host. 11c227063fSAndrew Brown Target { 12c227063fSAndrew Brown /// The target triple of the host. 13c227063fSAndrew Brown target: String, 14c227063fSAndrew Brown /// A list of CPU features to enable, e.g., `("has_avx", "false")`. 15c227063fSAndrew Brown flags: Vec<(String, String)>, 16c227063fSAndrew Brown }, 17c227063fSAndrew Brown } 18c227063fSAndrew Brown 19c227063fSAndrew Brown impl CodegenSettings { 20c227063fSAndrew Brown /// Configure Wasmtime with these codegen settings. configure(&self, config: &mut wasmtime_cli_flags::CommonOptions)21ba4e22bcSAlex Crichton pub fn configure(&self, config: &mut wasmtime_cli_flags::CommonOptions) { 22c227063fSAndrew Brown match self { 23c227063fSAndrew Brown CodegenSettings::Native => {} 24c227063fSAndrew Brown CodegenSettings::Target { target, flags } => { 25ba4e22bcSAlex Crichton config.target = Some(target.to_string()); 26c227063fSAndrew Brown for (key, value) in flags { 27ba4e22bcSAlex Crichton config 28ba4e22bcSAlex Crichton .codegen 29ba4e22bcSAlex Crichton .cranelift 30ba4e22bcSAlex Crichton .push((key.clone(), Some(value.clone()))); 31c227063fSAndrew Brown } 32c227063fSAndrew Brown } 33c227063fSAndrew Brown } 34c227063fSAndrew Brown } 354d75ebd1SJeffrey Charles 364d75ebd1SJeffrey Charles /// Returns the flags used for codegen. flags(&self) -> &[(String, String)]374d75ebd1SJeffrey Charles pub(crate) fn flags(&self) -> &[(String, String)] { 384d75ebd1SJeffrey Charles if let Self::Target { flags, .. } = self { 394d75ebd1SJeffrey Charles flags 404d75ebd1SJeffrey Charles } else { 414d75ebd1SJeffrey Charles &[] 424d75ebd1SJeffrey Charles } 434d75ebd1SJeffrey Charles } 44c227063fSAndrew Brown } 45c227063fSAndrew Brown 46c227063fSAndrew Brown impl<'a> Arbitrary<'a> for CodegenSettings { 4745b60bd6SAlex Crichton #[expect(unused_variables, reason = "macro-generated code")] arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self>48c227063fSAndrew Brown fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { 49c227063fSAndrew Brown // Helper macro to enable clif features based on what the native host 50c227063fSAndrew Brown // supports. If the input says to enable a feature and the host doesn't 51c227063fSAndrew Brown // support it then that test case is rejected with a warning. 52c227063fSAndrew Brown // 53c227063fSAndrew Brown // Note that this specifically consumes bytes from the fuzz input for 54c227063fSAndrew Brown // features for all targets, discarding anything which isn't applicable 55c227063fSAndrew Brown // to the current target. The theory behind this is that most fuzz bugs 56c227063fSAndrew Brown // won't be related to this feature selection so by consistently 57c227063fSAndrew Brown // consuming input irrespective of the current platform reproducing fuzz 58c227063fSAndrew Brown // bugs should be easier between different architectures. 59c227063fSAndrew Brown macro_rules! target_features { 60c227063fSAndrew Brown ( 61c227063fSAndrew Brown $( 62c227063fSAndrew Brown $arch:tt => { 63c227063fSAndrew Brown test:$test:ident, 64c227063fSAndrew Brown $(std: $std:tt => clif: $clif:tt $(ratio: $a:tt in $b:tt)?,)* 65c227063fSAndrew Brown }, 66c227063fSAndrew Brown )* 67c227063fSAndrew Brown ) => ({ 68c227063fSAndrew Brown let mut flags = Vec::new(); 69c227063fSAndrew Brown $( // for each `$arch` 70c227063fSAndrew Brown $( // for each `$std`/`$clif` pair 71c227063fSAndrew Brown // Use the input to generate whether `$clif` will be 72c227063fSAndrew Brown // enabled. By default this is a 1 in 2 chance but each 73c227063fSAndrew Brown // feature supports a custom ratio as well which shadows 74c227063fSAndrew Brown // the (low, hi) 75c227063fSAndrew Brown let (low, hi) = (1, 2); 76c227063fSAndrew Brown $(let (low, hi) = ($a, $b);)? 77c227063fSAndrew Brown let enable = u.ratio(low, hi)?; 78c227063fSAndrew Brown 79c227063fSAndrew Brown // If we're actually on the relevant platform and the 80c227063fSAndrew Brown // feature is enabled be sure to check that this host 81c227063fSAndrew Brown // supports it. If the host doesn't support it then 82c227063fSAndrew Brown // print a warning and return an error because this fuzz 83c227063fSAndrew Brown // input must be discarded. 84c227063fSAndrew Brown #[cfg(target_arch = $arch)] 85c227063fSAndrew Brown if enable && !std::arch::$test!($std) { 86c227063fSAndrew Brown log::warn!("want to enable clif `{}` but host doesn't support it", 87c227063fSAndrew Brown $clif); 88c227063fSAndrew Brown return Err(arbitrary::Error::EmptyChoose) 89c227063fSAndrew Brown } 90c227063fSAndrew Brown 91c227063fSAndrew Brown // And finally actually push the feature into the set of 92c227063fSAndrew Brown // flags to enable, but only if we're on the right 93c227063fSAndrew Brown // architecture. 94c227063fSAndrew Brown if cfg!(target_arch = $arch) { 95c227063fSAndrew Brown flags.push(( 96c227063fSAndrew Brown $clif.to_string(), 97c227063fSAndrew Brown enable.to_string(), 98c227063fSAndrew Brown )); 99c227063fSAndrew Brown } 100c227063fSAndrew Brown )* 101c227063fSAndrew Brown )* 102c227063fSAndrew Brown flags 103c227063fSAndrew Brown }) 104c227063fSAndrew Brown } 105c227063fSAndrew Brown if u.ratio(1, 10)? { 106c227063fSAndrew Brown let flags = target_features! { 107c227063fSAndrew Brown "x86_64" => { 108c227063fSAndrew Brown test: is_x86_feature_detected, 109c227063fSAndrew Brown 1103036e795Sbeetrees std:"cmpxchg16b" => clif:"has_cmpxchg16b", 1110c980788SAlex Crichton std:"sse3" => clif:"has_sse3", 1120c980788SAlex Crichton std:"ssse3" => clif:"has_ssse3", 1138fb41ca4SAlex Crichton std:"sse4.1" => clif:"has_sse41", 1142d25db04SAlex Crichton std:"sse4.2" => clif:"has_sse42", 115c227063fSAndrew Brown std:"popcnt" => clif:"has_popcnt", 116c227063fSAndrew Brown std:"avx" => clif:"has_avx", 117c227063fSAndrew Brown std:"avx2" => clif:"has_avx2", 11802c3b47dSAfonso Bordado std:"fma" => clif:"has_fma", 119c227063fSAndrew Brown std:"bmi1" => clif:"has_bmi1", 120c227063fSAndrew Brown std:"bmi2" => clif:"has_bmi2", 121c227063fSAndrew Brown std:"lzcnt" => clif:"has_lzcnt", 122c227063fSAndrew Brown 123*37553b2cSwithtimezone // not a lot of cpus support avx512 so these are weighted 124c227063fSAndrew Brown // to get enabled much less frequently. 125c227063fSAndrew Brown std:"avx512bitalg" => clif:"has_avx512bitalg" ratio:1 in 1000, 126c227063fSAndrew Brown std:"avx512dq" => clif:"has_avx512dq" ratio: 1 in 1000, 127c227063fSAndrew Brown std:"avx512f" => clif:"has_avx512f" ratio: 1 in 1000, 128c227063fSAndrew Brown std:"avx512vl" => clif:"has_avx512vl" ratio: 1 in 1000, 129c227063fSAndrew Brown std:"avx512vbmi" => clif:"has_avx512vbmi" ratio: 1 in 1000, 130c227063fSAndrew Brown }, 131c227063fSAndrew Brown "aarch64" => { 132c227063fSAndrew Brown test: is_aarch64_feature_detected, 133c227063fSAndrew Brown 134d8b29089SAnton Kirilov std: "bti" => clif: "use_bti", 135c227063fSAndrew Brown std: "lse" => clif: "has_lse", 1363f5c21bfSbeetrees std: "fp16" => clif: "has_fp16", 1371481721cSAnton Kirilov // even though the natural correspondence seems to be 1381481721cSAnton Kirilov // between "paca" and "has_pauth", the latter has no effect 1391481721cSAnton Kirilov // in isolation, so we actually use the setting that affects 1401481721cSAnton Kirilov // code generation 1411481721cSAnton Kirilov std: "paca" => clif: "sign_return_address", 1421481721cSAnton Kirilov // "paca" and "pacg" check for the same underlying 1431481721cSAnton Kirilov // architectural feature, so we use the latter to cover more 1441481721cSAnton Kirilov // code generation settings, of which we have chosen the one 1451481721cSAnton Kirilov // with the most significant effect 1461481721cSAnton Kirilov std: "pacg" => clif: "sign_return_address_all" ratio: 1 in 2, 147c227063fSAndrew Brown }, 148c227063fSAndrew Brown }; 149c227063fSAndrew Brown return Ok(CodegenSettings::Target { 150c227063fSAndrew Brown target: target_lexicon::Triple::host().to_string(), 151c227063fSAndrew Brown flags, 152c227063fSAndrew Brown }); 153c227063fSAndrew Brown } 154c227063fSAndrew Brown Ok(CodegenSettings::Native) 155c227063fSAndrew Brown } 156c227063fSAndrew Brown } 157