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