|
| 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, Type}; |
| 6 | +use cranelift::codegen::isa::CallConv; |
| 7 | + |
| 8 | +use arbitrary::Unstructured; |
| 9 | +use cranelift::prelude::{Ieee32, Ieee64}; |
| 10 | + |
| 11 | +/// A trait for generating random Cranelift datastructures. |
| 12 | +pub trait CraneliftArbitrary { |
| 13 | + fn _type(&mut self) -> Result<Type>; |
| 14 | + fn callconv(&mut self) -> Result<CallConv>; |
| 15 | + fn abi_param(&mut self) -> Result<AbiParam>; |
| 16 | + fn signature(&mut self, max_params: usize, max_rets: usize) -> Result<Signature>; |
| 17 | + fn datavalue(&mut self, ty: Type) -> Result<DataValue>; |
| 18 | +} |
| 19 | + |
| 20 | +impl<'a> CraneliftArbitrary for &mut Unstructured<'a> { |
| 21 | + fn _type(&mut self) -> Result<Type> { |
| 22 | + // TODO: It would be nice if we could get these directly from cranelift |
| 23 | + let scalars = [ |
| 24 | + I8, I16, I32, I64, I128, F32, F64, |
| 25 | + // R32, R64, |
| 26 | + ]; |
| 27 | + // TODO: vector types |
| 28 | + |
| 29 | + let ty = self.choose(&scalars[..])?; |
| 30 | + Ok(*ty) |
| 31 | + } |
| 32 | + |
| 33 | + fn callconv(&mut self) -> Result<CallConv> { |
| 34 | + // TODO: Generate random CallConvs per target |
| 35 | + Ok(CallConv::SystemV) |
| 36 | + } |
| 37 | + |
| 38 | + fn abi_param(&mut self) -> Result<AbiParam> { |
| 39 | + let value_type = self._type()?; |
| 40 | + // TODO: There are more argument purposes to be explored... |
| 41 | + let purpose = ArgumentPurpose::Normal; |
| 42 | + let extension = if value_type.is_int() { |
| 43 | + *self.choose(&[ |
| 44 | + ArgumentExtension::Sext, |
| 45 | + ArgumentExtension::Uext, |
| 46 | + ArgumentExtension::None, |
| 47 | + ])? |
| 48 | + } else { |
| 49 | + ArgumentExtension::None |
| 50 | + }; |
| 51 | + |
| 52 | + Ok(AbiParam { |
| 53 | + value_type, |
| 54 | + purpose, |
| 55 | + extension, |
| 56 | + }) |
| 57 | + } |
| 58 | + |
| 59 | + fn signature(&mut self, max_params: usize, max_rets: usize) -> Result<Signature> { |
| 60 | + let callconv = self.callconv()?; |
| 61 | + let mut sig = Signature::new(callconv); |
| 62 | + |
| 63 | + for _ in 0..max_params { |
| 64 | + sig.params.push(self.abi_param()?); |
| 65 | + } |
| 66 | + |
| 67 | + for _ in 0..max_rets { |
| 68 | + sig.returns.push(self.abi_param()?); |
| 69 | + } |
| 70 | + |
| 71 | + Ok(sig) |
| 72 | + } |
| 73 | + |
| 74 | + fn datavalue(&mut self, ty: Type) -> Result<DataValue> { |
| 75 | + Ok(match ty { |
| 76 | + ty if ty.is_int() => { |
| 77 | + let imm = match ty { |
| 78 | + I8 => self.arbitrary::<i8>()? as i128, |
| 79 | + I16 => self.arbitrary::<i16>()? as i128, |
| 80 | + I32 => self.arbitrary::<i32>()? as i128, |
| 81 | + I64 => self.arbitrary::<i64>()? as i128, |
| 82 | + I128 => self.arbitrary::<i128>()?, |
| 83 | + _ => unreachable!(), |
| 84 | + }; |
| 85 | + DataValue::from_integer(imm, ty)? |
| 86 | + } |
| 87 | + // f{32,64}::arbitrary does not generate a bunch of important values |
| 88 | + // such as Signaling NaN's / NaN's with payload, so generate floats from integers. |
| 89 | + F32 => DataValue::F32(Ieee32::with_bits(self.arbitrary::<u32>()?)), |
| 90 | + F64 => DataValue::F64(Ieee64::with_bits(self.arbitrary::<u64>()?)), |
| 91 | + _ => unimplemented!(), |
| 92 | + }) |
| 93 | + } |
| 94 | +} |
0 commit comments