1 use crate::config::Config; 2 use anyhow::Result; 3 use arbitrary::Unstructured; 4 use cranelift::codegen::ir::types::*; 5 use cranelift::codegen::ir::{AbiParam, ExternalName, Function, Opcode, Signature, Type, Value}; 6 use cranelift::codegen::isa::CallConv; 7 use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; 8 use cranelift::prelude::{EntityRef, InstBuilder}; 9 10 fn insert_opcode_arity_0( 11 _fgen: &mut FunctionGenerator, 12 builder: &mut FunctionBuilder, 13 opcode: Opcode, 14 _args: &'static [Type], 15 _rets: &'static [Type], 16 ) -> Result<()> { 17 builder.ins().NullAry(opcode, INVALID); 18 Ok(()) 19 } 20 21 fn insert_opcode_arity_2( 22 fgen: &mut FunctionGenerator, 23 builder: &mut FunctionBuilder, 24 opcode: Opcode, 25 args: &'static [Type], 26 rets: &'static [Type], 27 ) -> Result<()> { 28 let arg0 = fgen.get_variable_of_type(args[0])?; 29 let arg0 = builder.use_var(arg0); 30 31 let arg1 = fgen.get_variable_of_type(args[1])?; 32 let arg1 = builder.use_var(arg1); 33 34 let typevar = rets[0]; 35 let (inst, dfg) = builder.ins().Binary(opcode, typevar, arg0, arg1); 36 let results = dfg.inst_results(inst).to_vec(); 37 38 for (val, ty) in results.into_iter().zip(rets) { 39 let var = fgen.get_variable_of_type(*ty)?; 40 builder.def_var(var, val); 41 } 42 Ok(()) 43 } 44 45 type OpcodeInserter = fn( 46 fgen: &mut FunctionGenerator, 47 builder: &mut FunctionBuilder, 48 Opcode, 49 &'static [Type], 50 &'static [Type], 51 ) -> Result<()>; 52 53 // TODO: Derive this from the `cranelift-meta` generator. 54 const OPCODE_SIGNATURES: &'static [( 55 Opcode, 56 &'static [Type], // Args 57 &'static [Type], // Rets 58 OpcodeInserter, 59 )] = &[ 60 (Opcode::Nop, &[], &[], insert_opcode_arity_0), 61 // Iadd 62 (Opcode::Iadd, &[I8, I8], &[I8], insert_opcode_arity_2), 63 (Opcode::Iadd, &[I16, I16], &[I16], insert_opcode_arity_2), 64 (Opcode::Iadd, &[I32, I32], &[I32], insert_opcode_arity_2), 65 (Opcode::Iadd, &[I64, I64], &[I64], insert_opcode_arity_2), 66 // Isub 67 (Opcode::Isub, &[I8, I8], &[I8], insert_opcode_arity_2), 68 (Opcode::Isub, &[I16, I16], &[I16], insert_opcode_arity_2), 69 (Opcode::Isub, &[I32, I32], &[I32], insert_opcode_arity_2), 70 (Opcode::Isub, &[I64, I64], &[I64], insert_opcode_arity_2), 71 // Imul 72 (Opcode::Imul, &[I8, I8], &[I8], insert_opcode_arity_2), 73 (Opcode::Imul, &[I16, I16], &[I16], insert_opcode_arity_2), 74 (Opcode::Imul, &[I32, I32], &[I32], insert_opcode_arity_2), 75 (Opcode::Imul, &[I64, I64], &[I64], insert_opcode_arity_2), 76 // Udiv 77 (Opcode::Udiv, &[I8, I8], &[I8], insert_opcode_arity_2), 78 (Opcode::Udiv, &[I16, I16], &[I16], insert_opcode_arity_2), 79 (Opcode::Udiv, &[I32, I32], &[I32], insert_opcode_arity_2), 80 (Opcode::Udiv, &[I64, I64], &[I64], insert_opcode_arity_2), 81 // Sdiv 82 (Opcode::Sdiv, &[I8, I8], &[I8], insert_opcode_arity_2), 83 (Opcode::Sdiv, &[I16, I16], &[I16], insert_opcode_arity_2), 84 (Opcode::Sdiv, &[I32, I32], &[I32], insert_opcode_arity_2), 85 (Opcode::Sdiv, &[I64, I64], &[I64], insert_opcode_arity_2), 86 ]; 87 88 pub struct FunctionGenerator<'r, 'data> 89 where 90 'data: 'r, 91 { 92 u: &'r mut Unstructured<'data>, 93 config: &'r Config, 94 vars: Vec<(Type, Variable)>, 95 } 96 97 impl<'r, 'data> FunctionGenerator<'r, 'data> 98 where 99 'data: 'r, 100 { 101 pub fn new(u: &'r mut Unstructured<'data>, config: &'r Config) -> Self { 102 Self { 103 u, 104 config, 105 vars: vec![], 106 } 107 } 108 109 fn generate_callconv(&mut self) -> Result<CallConv> { 110 // TODO: Generate random CallConvs per target 111 Ok(CallConv::SystemV) 112 } 113 114 fn generate_type(&mut self) -> Result<Type> { 115 // TODO: It would be nice if we could get these directly from cranelift 116 let scalars = [ 117 // IFLAGS, FFLAGS, 118 // B1, B8, B16, B32, B64, B128, 119 I8, I16, I32, I64, 120 // I128, 121 // F32, F64, 122 // R32, R64, 123 ]; 124 // TODO: vector types 125 126 let ty = self.u.choose(&scalars[..])?; 127 Ok(*ty) 128 } 129 130 fn generate_abi_param(&mut self) -> Result<AbiParam> { 131 // TODO: Generate more advanced abi params (structs/purposes/extensions/etc...) 132 let ty = self.generate_type()?; 133 Ok(AbiParam::new(ty)) 134 } 135 136 fn generate_signature(&mut self) -> Result<Signature> { 137 let callconv = self.generate_callconv()?; 138 let mut sig = Signature::new(callconv); 139 140 for _ in 0..self.u.int_in_range(self.config.signature_params.clone())? { 141 sig.params.push(self.generate_abi_param()?); 142 } 143 144 for _ in 0..self.u.int_in_range(self.config.signature_rets.clone())? { 145 sig.returns.push(self.generate_abi_param()?); 146 } 147 148 Ok(sig) 149 } 150 151 /// Creates a new var 152 fn create_var(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Variable> { 153 let id = self.vars.len(); 154 let var = Variable::new(id); 155 builder.declare_var(var, ty); 156 self.vars.push((ty, var)); 157 Ok(var) 158 } 159 160 fn vars_of_type(&self, ty: Type) -> Vec<Variable> { 161 self.vars 162 .iter() 163 .filter(|(var_ty, _)| *var_ty == ty) 164 .map(|(_, v)| *v) 165 .collect() 166 } 167 168 /// Get a variable of type `ty` from the current function 169 fn get_variable_of_type(&mut self, ty: Type) -> Result<Variable> { 170 let opts = self.vars_of_type(ty); 171 let var = self.u.choose(&opts[..])?; 172 Ok(*var) 173 } 174 175 /// Generates an instruction(`iconst`/`fconst`/etc...) to introduce a constant value 176 fn generate_const(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Value> { 177 let imm64 = match ty { 178 I8 => self.u.arbitrary::<i8>()? as i64, 179 I16 => self.u.arbitrary::<i16>()? as i64, 180 I32 => self.u.arbitrary::<i32>()? as i64, 181 I64 => self.u.arbitrary::<i64>()?, 182 _ => unreachable!(), 183 }; 184 let val = builder.ins().iconst(ty, imm64); 185 186 Ok(val) 187 } 188 189 fn generate_return(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 190 let ret_params = builder.func.signature.returns.clone(); 191 192 let vars = ret_params 193 .iter() 194 .map(|p| self.get_variable_of_type(p.value_type)) 195 .collect::<Result<Vec<_>>>()?; 196 197 let vals = vars 198 .into_iter() 199 .map(|v| builder.use_var(v)) 200 .collect::<Vec<_>>(); 201 202 builder.ins().return_(&vals[..]); 203 Ok(()) 204 } 205 206 /// Inserts a random instruction into the block 207 fn generate_instruction(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 208 let (op, args, rets, inserter) = *self.u.choose(OPCODE_SIGNATURES)?; 209 inserter(self, builder, op, args, rets) 210 } 211 212 pub fn generate(mut self) -> Result<Function> { 213 let sig = self.generate_signature()?; 214 215 let mut fn_builder_ctx = FunctionBuilderContext::new(); 216 let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone()); 217 218 let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); 219 let block0 = builder.create_block(); 220 builder.append_block_params_for_function_params(block0); 221 builder.switch_to_block(block0); 222 builder.seal_block(block0); 223 224 // Define variables for the function signature 225 for (i, param) in sig.params.iter().enumerate() { 226 let var = self.create_var(&mut builder, param.value_type)?; 227 let block_param = builder.block_params(block0)[i]; 228 builder.def_var(var, block_param); 229 } 230 231 // Create a pool of vars that are going to be used in this function 232 for _ in 0..self.u.int_in_range(self.config.vars_per_function.clone())? { 233 let ty = self.generate_type()?; 234 let var = self.create_var(&mut builder, ty)?; 235 let value = self.generate_const(&mut builder, ty)?; 236 builder.def_var(var, value); 237 } 238 239 for _ in 0..self 240 .u 241 .int_in_range(self.config.instructions_per_block.clone())? 242 { 243 self.generate_instruction(&mut builder)?; 244 } 245 246 // TODO: We should make this part of the regular instruction selection 247 self.generate_return(&mut builder)?; 248 249 builder.finalize(); 250 251 Ok(func) 252 } 253 } 254