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