Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/fuzzgen/src/cranelift_arbitrary.rs
1692 views
1
use crate::codegen::ir::{ArgumentExtension, ArgumentPurpose};
2
use anyhow::Result;
3
use cranelift::codegen::data_value::DataValue;
4
use cranelift::codegen::ir::types::*;
5
use cranelift::codegen::ir::{AbiParam, Signature};
6
use cranelift::codegen::isa::CallConv;
7
8
use arbitrary::Unstructured;
9
use cranelift::prelude::{Ieee32, Ieee64};
10
use target_lexicon::Architecture;
11
12
/// A trait for generating random Cranelift datastructures.
13
pub trait CraneliftArbitrary {
14
fn _type(&mut self, simd_enabled: bool) -> Result<Type>;
15
fn callconv(&mut self, architecture: Architecture) -> Result<CallConv>;
16
fn abi_param(&mut self, simd_enabled: bool) -> Result<AbiParam>;
17
fn signature(
18
&mut self,
19
simd_enabled: bool,
20
architecture: Architecture,
21
max_params: usize,
22
max_rets: usize,
23
) -> Result<Signature>;
24
fn datavalue(&mut self, ty: Type) -> Result<DataValue>;
25
}
26
27
impl<'a> CraneliftArbitrary for &mut Unstructured<'a> {
28
fn _type(&mut self, simd_enabled: bool) -> Result<Type> {
29
// TODO: It would be nice if we could get these directly from cranelift
30
let choices: &[Type] = if simd_enabled {
31
&[
32
I8, I16, I32, I64, I128, // Scalar Integers
33
F32, F64, // Scalar Floats
34
I8X16, I16X8, I32X4, I64X2, // SIMD Integers
35
F32X4, F64X2, // SIMD Floats
36
]
37
} else {
38
&[I8, I16, I32, I64, I128, F32, F64]
39
};
40
41
Ok(*self.choose(choices)?)
42
}
43
44
fn callconv(&mut self, architecture: Architecture) -> Result<CallConv> {
45
// These are implemented and should work on all backends
46
let mut allowed_callconvs = vec![
47
CallConv::Fast,
48
CallConv::Cold,
49
CallConv::SystemV,
50
CallConv::Tail,
51
];
52
53
// Fastcall is supposed to work on x86 and aarch64
54
if matches!(
55
architecture,
56
Architecture::X86_64 | Architecture::Aarch64(_)
57
) {
58
allowed_callconvs.push(CallConv::WindowsFastcall);
59
}
60
61
// AArch64 has a few Apple specific calling conventions
62
if matches!(architecture, Architecture::Aarch64(_)) {
63
allowed_callconvs.push(CallConv::AppleAarch64);
64
}
65
66
// The winch calling convention is supposed to work on x64.
67
if matches!(architecture, Architecture::X86_64) {
68
allowed_callconvs.push(CallConv::Winch);
69
}
70
71
Ok(*self.choose(&allowed_callconvs[..])?)
72
}
73
74
fn abi_param(&mut self, simd_enabled: bool) -> Result<AbiParam> {
75
let value_type = self._type(simd_enabled)?;
76
// TODO: There are more argument purposes to be explored...
77
let purpose = ArgumentPurpose::Normal;
78
let extension = if value_type.is_int() {
79
*self.choose(&[
80
ArgumentExtension::Sext,
81
ArgumentExtension::Uext,
82
ArgumentExtension::None,
83
])?
84
} else {
85
ArgumentExtension::None
86
};
87
88
Ok(AbiParam {
89
value_type,
90
purpose,
91
extension,
92
})
93
}
94
95
fn signature(
96
&mut self,
97
mut simd_enabled: bool,
98
architecture: Architecture,
99
max_params: usize,
100
max_rets: usize,
101
) -> Result<Signature> {
102
let callconv = self.callconv(architecture)?;
103
104
// Winch doesn't support SIMD yet
105
// https://github.com/bytecodealliance/wasmtime/issues/8093
106
if callconv == CallConv::Winch {
107
simd_enabled = false;
108
}
109
110
let mut sig = Signature::new(callconv);
111
112
for _ in 0..max_params {
113
sig.params.push(self.abi_param(simd_enabled)?);
114
}
115
116
for _ in 0..max_rets {
117
sig.returns.push(self.abi_param(simd_enabled)?);
118
}
119
120
Ok(sig)
121
}
122
123
fn datavalue(&mut self, ty: Type) -> Result<DataValue> {
124
Ok(match ty {
125
ty if ty.is_int() => {
126
let imm = match ty {
127
I8 => self.arbitrary::<i8>()? as i128,
128
I16 => self.arbitrary::<i16>()? as i128,
129
I32 => self.arbitrary::<i32>()? as i128,
130
I64 => self.arbitrary::<i64>()? as i128,
131
I128 => self.arbitrary::<i128>()?,
132
_ => unreachable!(),
133
};
134
DataValue::from_integer(imm, ty)?
135
}
136
// f{32,64}::arbitrary does not generate a bunch of important values
137
// such as Signaling NaN's / NaN's with payload, so generate floats from integers.
138
F32 => DataValue::F32(Ieee32::with_bits(self.arbitrary::<u32>()?)),
139
F64 => DataValue::F64(Ieee64::with_bits(self.arbitrary::<u64>()?)),
140
ty if ty.is_vector() && ty.bits() == 128 => {
141
DataValue::V128(self.arbitrary::<[u8; 16]>()?)
142
}
143
_ => unimplemented!(),
144
})
145
}
146
}
147
148