cranelift_fuzzgen/
cranelift_arbitrary.rs1use crate::codegen::ir::{ArgumentExtension, ArgumentPurpose};
2use anyhow::Result;
3use cranelift::codegen::data_value::DataValue;
4use cranelift::codegen::ir::types::*;
5use cranelift::codegen::ir::{AbiParam, Signature};
6use cranelift::codegen::isa::CallConv;
7
8use arbitrary::Unstructured;
9use cranelift::prelude::{Ieee32, Ieee64};
10use target_lexicon::Architecture;
11
12pub 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
27impl<'a> CraneliftArbitrary for &mut Unstructured<'a> {
28 fn _type(&mut self, simd_enabled: bool) -> Result<Type> {
29 let choices: &[Type] = if simd_enabled {
31 &[
32 I8, I16, I32, I64, I128, F32, F64, I8X16, I16X8, I32X4, I64X2, F32X4, F64X2, ]
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 let mut allowed_callconvs = vec![
47 CallConv::Fast,
48 CallConv::Cold,
49 CallConv::SystemV,
50 CallConv::Tail,
51 ];
52
53 if matches!(
55 architecture,
56 Architecture::X86_64 | Architecture::Aarch64(_)
57 ) {
58 allowed_callconvs.push(CallConv::WindowsFastcall);
59 }
60
61 if matches!(architecture, Architecture::Aarch64(_)) {
63 allowed_callconvs.push(CallConv::AppleAarch64);
64 }
65
66 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 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 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 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}