1 use crate::codegen::ir::{ArgumentExtension, ArgumentPurpose};
2 use crate::config::Config;
3 use anyhow::Result;
4 use arbitrary::{Arbitrary, Unstructured};
5 use cranelift::codegen::ir::immediates::Offset32;
6 use cranelift::codegen::ir::instructions::InstructionFormat;
7 use cranelift::codegen::ir::stackslot::StackSize;
8 use cranelift::codegen::ir::{types::*, FuncRef, LibCall, UserExternalName, UserFuncName};
9 use cranelift::codegen::ir::{
10     AbiParam, Block, ExternalName, Function, JumpTable, Opcode, Signature, StackSlot, Type, Value,
11 };
12 use cranelift::codegen::isa::CallConv;
13 use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Switch, Variable};
14 use cranelift::prelude::{
15     EntityRef, ExtFuncData, FloatCC, InstBuilder, IntCC, JumpTableData, MemFlags, StackSlotData,
16     StackSlotKind,
17 };
18 use std::collections::HashMap;
19 use std::ops::RangeInclusive;
20 
21 type BlockSignature = Vec<Type>;
22 
23 fn insert_opcode(
24     fgen: &mut FunctionGenerator,
25     builder: &mut FunctionBuilder,
26     opcode: Opcode,
27     args: &'static [Type],
28     rets: &'static [Type],
29 ) -> Result<()> {
30     let mut vals = Vec::with_capacity(args.len());
31     for &arg in args.into_iter() {
32         let var = fgen.get_variable_of_type(arg)?;
33         let val = builder.use_var(var);
34         vals.push(val);
35     }
36 
37     // For pretty much every instruction the control type is the return type
38     // except for Iconcat and Isplit which are *special* and the control type
39     // is the input type.
40     let ctrl_type = if opcode == Opcode::Iconcat || opcode == Opcode::Isplit {
41         args.first()
42     } else {
43         rets.first()
44     }
45     .copied()
46     .unwrap_or(INVALID);
47 
48     // Choose the appropriate instruction format for this opcode
49     let (inst, dfg) = match opcode.format() {
50         InstructionFormat::NullAry => builder.ins().NullAry(opcode, ctrl_type),
51         InstructionFormat::Unary => builder.ins().Unary(opcode, ctrl_type, vals[0]),
52         InstructionFormat::Binary => builder.ins().Binary(opcode, ctrl_type, vals[0], vals[1]),
53         InstructionFormat::Ternary => builder
54             .ins()
55             .Ternary(opcode, ctrl_type, vals[0], vals[1], vals[2]),
56         _ => unimplemented!(),
57     };
58     let results = dfg.inst_results(inst).to_vec();
59 
60     for (val, &ty) in results.into_iter().zip(rets) {
61         let var = fgen.get_variable_of_type(ty)?;
62         builder.def_var(var, val);
63     }
64     Ok(())
65 }
66 
67 fn insert_call(
68     fgen: &mut FunctionGenerator,
69     builder: &mut FunctionBuilder,
70     opcode: Opcode,
71     _args: &'static [Type],
72     _rets: &'static [Type],
73 ) -> Result<()> {
74     assert_eq!(opcode, Opcode::Call, "only call handled at the moment");
75     let (sig, func_ref) = fgen.u.choose(&fgen.resources.func_refs)?.clone();
76 
77     let actuals = fgen.generate_values_for_signature(
78         builder,
79         sig.params.iter().map(|abi_param| abi_param.value_type),
80     )?;
81 
82     builder.ins().call(func_ref, &actuals);
83     Ok(())
84 }
85 
86 fn insert_stack_load(
87     fgen: &mut FunctionGenerator,
88     builder: &mut FunctionBuilder,
89     _opcode: Opcode,
90     _args: &'static [Type],
91     rets: &'static [Type],
92 ) -> Result<()> {
93     let typevar = rets[0];
94     let type_size = typevar.bytes();
95     let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?;
96     let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32;
97 
98     let val = builder.ins().stack_load(typevar, slot, offset);
99     let var = fgen.get_variable_of_type(typevar)?;
100     builder.def_var(var, val);
101 
102     Ok(())
103 }
104 
105 fn insert_stack_store(
106     fgen: &mut FunctionGenerator,
107     builder: &mut FunctionBuilder,
108     _opcode: Opcode,
109     args: &'static [Type],
110     _rets: &'static [Type],
111 ) -> Result<()> {
112     let typevar = args[0];
113     let type_size = typevar.bytes();
114     let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?;
115     let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32;
116 
117     let arg0 = fgen.get_variable_of_type(typevar)?;
118     let arg0 = builder.use_var(arg0);
119 
120     builder.ins().stack_store(arg0, slot, offset);
121     Ok(())
122 }
123 
124 fn insert_cmp(
125     fgen: &mut FunctionGenerator,
126     builder: &mut FunctionBuilder,
127     opcode: Opcode,
128     args: &'static [Type],
129     rets: &'static [Type],
130 ) -> Result<()> {
131     let lhs = fgen.get_variable_of_type(args[0])?;
132     let lhs = builder.use_var(lhs);
133 
134     let rhs = fgen.get_variable_of_type(args[1])?;
135     let rhs = builder.use_var(rhs);
136 
137     let res = if opcode == Opcode::Fcmp {
138         // Some FloatCC's are not implemented on AArch64, see:
139         // https://github.com/bytecodealliance/wasmtime/issues/4850
140         let float_cc = if cfg!(target_arch = "aarch64") {
141             &[
142                 FloatCC::Ordered,
143                 FloatCC::Unordered,
144                 FloatCC::Equal,
145                 FloatCC::NotEqual,
146                 FloatCC::LessThan,
147                 FloatCC::LessThanOrEqual,
148                 FloatCC::GreaterThan,
149                 FloatCC::GreaterThanOrEqual,
150             ]
151         } else {
152             FloatCC::all()
153         };
154 
155         let cc = *fgen.u.choose(float_cc)?;
156         builder.ins().fcmp(cc, lhs, rhs)
157     } else {
158         let cc = *fgen.u.choose(IntCC::all())?;
159         builder.ins().icmp(cc, lhs, rhs)
160     };
161 
162     let var = fgen.get_variable_of_type(rets[0])?;
163     builder.def_var(var, res);
164 
165     Ok(())
166 }
167 
168 fn insert_const(
169     fgen: &mut FunctionGenerator,
170     builder: &mut FunctionBuilder,
171     _opcode: Opcode,
172     _args: &'static [Type],
173     rets: &'static [Type],
174 ) -> Result<()> {
175     let typevar = rets[0];
176     let var = fgen.get_variable_of_type(typevar)?;
177     let val = fgen.generate_const(builder, typevar)?;
178     builder.def_var(var, val);
179     Ok(())
180 }
181 
182 fn insert_load_store(
183     fgen: &mut FunctionGenerator,
184     builder: &mut FunctionBuilder,
185     opcode: Opcode,
186     args: &'static [Type],
187     rets: &'static [Type],
188 ) -> Result<()> {
189     let ctrl_type = *rets.first().or(args.first()).unwrap();
190     let type_size = ctrl_type.bytes();
191     let (address, offset) = fgen.generate_load_store_address(builder, type_size)?;
192 
193     // TODO: More advanced MemFlags
194     let flags = MemFlags::new();
195 
196     // The variable being loaded or stored into
197     let var = fgen.get_variable_of_type(ctrl_type)?;
198 
199     if opcode.can_store() {
200         let val = builder.use_var(var);
201 
202         builder
203             .ins()
204             .Store(opcode, ctrl_type, flags, offset, val, address);
205     } else {
206         let (inst, dfg) = builder
207             .ins()
208             .Load(opcode, ctrl_type, flags, offset, address);
209 
210         let new_val = dfg.first_result(inst);
211         builder.def_var(var, new_val);
212     }
213 
214     Ok(())
215 }
216 
217 type OpcodeInserter = fn(
218     fgen: &mut FunctionGenerator,
219     builder: &mut FunctionBuilder,
220     Opcode,
221     &'static [Type],
222     &'static [Type],
223 ) -> Result<()>;
224 
225 // TODO: Derive this from the `cranelift-meta` generator.
226 const OPCODE_SIGNATURES: &'static [(
227     Opcode,
228     &'static [Type], // Args
229     &'static [Type], // Rets
230     OpcodeInserter,
231 )] = &[
232     (Opcode::Nop, &[], &[], insert_opcode),
233     // Iadd
234     (Opcode::Iadd, &[I8, I8], &[I8], insert_opcode),
235     (Opcode::Iadd, &[I16, I16], &[I16], insert_opcode),
236     (Opcode::Iadd, &[I32, I32], &[I32], insert_opcode),
237     (Opcode::Iadd, &[I64, I64], &[I64], insert_opcode),
238     (Opcode::Iadd, &[I128, I128], &[I128], insert_opcode),
239     // Isub
240     (Opcode::Isub, &[I8, I8], &[I8], insert_opcode),
241     (Opcode::Isub, &[I16, I16], &[I16], insert_opcode),
242     (Opcode::Isub, &[I32, I32], &[I32], insert_opcode),
243     (Opcode::Isub, &[I64, I64], &[I64], insert_opcode),
244     (Opcode::Isub, &[I128, I128], &[I128], insert_opcode),
245     // Imul
246     (Opcode::Imul, &[I8, I8], &[I8], insert_opcode),
247     (Opcode::Imul, &[I16, I16], &[I16], insert_opcode),
248     (Opcode::Imul, &[I32, I32], &[I32], insert_opcode),
249     (Opcode::Imul, &[I64, I64], &[I64], insert_opcode),
250     (Opcode::Imul, &[I128, I128], &[I128], insert_opcode),
251     // Udiv
252     (Opcode::Udiv, &[I8, I8], &[I8], insert_opcode),
253     (Opcode::Udiv, &[I16, I16], &[I16], insert_opcode),
254     (Opcode::Udiv, &[I32, I32], &[I32], insert_opcode),
255     (Opcode::Udiv, &[I64, I64], &[I64], insert_opcode),
256     // udiv.i128 not implemented in some backends:
257     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4756
258     //   aarch64: https://github.com/bytecodealliance/wasmtime/issues/4864
259     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
260     (Opcode::Udiv, &[I128, I128], &[I128], insert_opcode),
261     // Sdiv
262     (Opcode::Sdiv, &[I8, I8], &[I8], insert_opcode),
263     (Opcode::Sdiv, &[I16, I16], &[I16], insert_opcode),
264     (Opcode::Sdiv, &[I32, I32], &[I32], insert_opcode),
265     (Opcode::Sdiv, &[I64, I64], &[I64], insert_opcode),
266     // sdiv.i128 not implemented in some backends:
267     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4770
268     //   aarch64: https://github.com/bytecodealliance/wasmtime/issues/4864
269     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
270     (Opcode::Sdiv, &[I128, I128], &[I128], insert_opcode),
271     // Rotr
272     (Opcode::Rotr, &[I8, I8], &[I8], insert_opcode),
273     (Opcode::Rotr, &[I8, I16], &[I8], insert_opcode),
274     (Opcode::Rotr, &[I8, I32], &[I8], insert_opcode),
275     (Opcode::Rotr, &[I8, I64], &[I8], insert_opcode),
276     (Opcode::Rotr, &[I8, I128], &[I8], insert_opcode),
277     (Opcode::Rotr, &[I16, I8], &[I16], insert_opcode),
278     (Opcode::Rotr, &[I16, I16], &[I16], insert_opcode),
279     (Opcode::Rotr, &[I16, I32], &[I16], insert_opcode),
280     (Opcode::Rotr, &[I16, I64], &[I16], insert_opcode),
281     (Opcode::Rotr, &[I16, I128], &[I16], insert_opcode),
282     (Opcode::Rotr, &[I32, I8], &[I32], insert_opcode),
283     (Opcode::Rotr, &[I32, I16], &[I32], insert_opcode),
284     (Opcode::Rotr, &[I32, I32], &[I32], insert_opcode),
285     (Opcode::Rotr, &[I32, I64], &[I32], insert_opcode),
286     (Opcode::Rotr, &[I32, I128], &[I32], insert_opcode),
287     (Opcode::Rotr, &[I64, I8], &[I64], insert_opcode),
288     (Opcode::Rotr, &[I64, I16], &[I64], insert_opcode),
289     (Opcode::Rotr, &[I64, I32], &[I64], insert_opcode),
290     (Opcode::Rotr, &[I64, I64], &[I64], insert_opcode),
291     (Opcode::Rotr, &[I64, I128], &[I64], insert_opcode),
292     (Opcode::Rotr, &[I128, I8], &[I128], insert_opcode),
293     (Opcode::Rotr, &[I128, I16], &[I128], insert_opcode),
294     (Opcode::Rotr, &[I128, I32], &[I128], insert_opcode),
295     (Opcode::Rotr, &[I128, I64], &[I128], insert_opcode),
296     (Opcode::Rotr, &[I128, I128], &[I128], insert_opcode),
297     // Rotl
298     (Opcode::Rotl, &[I8, I8], &[I8], insert_opcode),
299     (Opcode::Rotl, &[I8, I16], &[I8], insert_opcode),
300     (Opcode::Rotl, &[I8, I32], &[I8], insert_opcode),
301     (Opcode::Rotl, &[I8, I64], &[I8], insert_opcode),
302     (Opcode::Rotl, &[I8, I128], &[I8], insert_opcode),
303     (Opcode::Rotl, &[I16, I8], &[I16], insert_opcode),
304     (Opcode::Rotl, &[I16, I16], &[I16], insert_opcode),
305     (Opcode::Rotl, &[I16, I32], &[I16], insert_opcode),
306     (Opcode::Rotl, &[I16, I64], &[I16], insert_opcode),
307     (Opcode::Rotl, &[I16, I128], &[I16], insert_opcode),
308     (Opcode::Rotl, &[I32, I8], &[I32], insert_opcode),
309     (Opcode::Rotl, &[I32, I16], &[I32], insert_opcode),
310     (Opcode::Rotl, &[I32, I32], &[I32], insert_opcode),
311     (Opcode::Rotl, &[I32, I64], &[I32], insert_opcode),
312     (Opcode::Rotl, &[I32, I128], &[I32], insert_opcode),
313     (Opcode::Rotl, &[I64, I8], &[I64], insert_opcode),
314     (Opcode::Rotl, &[I64, I16], &[I64], insert_opcode),
315     (Opcode::Rotl, &[I64, I32], &[I64], insert_opcode),
316     (Opcode::Rotl, &[I64, I64], &[I64], insert_opcode),
317     (Opcode::Rotl, &[I64, I128], &[I64], insert_opcode),
318     (Opcode::Rotl, &[I128, I8], &[I128], insert_opcode),
319     (Opcode::Rotl, &[I128, I16], &[I128], insert_opcode),
320     (Opcode::Rotl, &[I128, I32], &[I128], insert_opcode),
321     (Opcode::Rotl, &[I128, I64], &[I128], insert_opcode),
322     (Opcode::Rotl, &[I128, I128], &[I128], insert_opcode),
323     // Ishl
324     (Opcode::Ishl, &[I8, I8], &[I8], insert_opcode),
325     (Opcode::Ishl, &[I8, I16], &[I8], insert_opcode),
326     (Opcode::Ishl, &[I8, I32], &[I8], insert_opcode),
327     (Opcode::Ishl, &[I8, I64], &[I8], insert_opcode),
328     (Opcode::Ishl, &[I8, I128], &[I8], insert_opcode),
329     (Opcode::Ishl, &[I16, I8], &[I16], insert_opcode),
330     (Opcode::Ishl, &[I16, I16], &[I16], insert_opcode),
331     (Opcode::Ishl, &[I16, I32], &[I16], insert_opcode),
332     (Opcode::Ishl, &[I16, I64], &[I16], insert_opcode),
333     (Opcode::Ishl, &[I16, I128], &[I16], insert_opcode),
334     (Opcode::Ishl, &[I32, I8], &[I32], insert_opcode),
335     (Opcode::Ishl, &[I32, I16], &[I32], insert_opcode),
336     (Opcode::Ishl, &[I32, I32], &[I32], insert_opcode),
337     (Opcode::Ishl, &[I32, I64], &[I32], insert_opcode),
338     (Opcode::Ishl, &[I32, I128], &[I32], insert_opcode),
339     (Opcode::Ishl, &[I64, I8], &[I64], insert_opcode),
340     (Opcode::Ishl, &[I64, I16], &[I64], insert_opcode),
341     (Opcode::Ishl, &[I64, I32], &[I64], insert_opcode),
342     (Opcode::Ishl, &[I64, I64], &[I64], insert_opcode),
343     (Opcode::Ishl, &[I64, I128], &[I64], insert_opcode),
344     (Opcode::Ishl, &[I128, I8], &[I128], insert_opcode),
345     (Opcode::Ishl, &[I128, I16], &[I128], insert_opcode),
346     (Opcode::Ishl, &[I128, I32], &[I128], insert_opcode),
347     (Opcode::Ishl, &[I128, I64], &[I128], insert_opcode),
348     (Opcode::Ishl, &[I128, I128], &[I128], insert_opcode),
349     // Sshr
350     (Opcode::Sshr, &[I8, I8], &[I8], insert_opcode),
351     (Opcode::Sshr, &[I8, I16], &[I8], insert_opcode),
352     (Opcode::Sshr, &[I8, I32], &[I8], insert_opcode),
353     (Opcode::Sshr, &[I8, I64], &[I8], insert_opcode),
354     (Opcode::Sshr, &[I8, I128], &[I8], insert_opcode),
355     (Opcode::Sshr, &[I16, I8], &[I16], insert_opcode),
356     (Opcode::Sshr, &[I16, I16], &[I16], insert_opcode),
357     (Opcode::Sshr, &[I16, I32], &[I16], insert_opcode),
358     (Opcode::Sshr, &[I16, I64], &[I16], insert_opcode),
359     (Opcode::Sshr, &[I16, I128], &[I16], insert_opcode),
360     (Opcode::Sshr, &[I32, I8], &[I32], insert_opcode),
361     (Opcode::Sshr, &[I32, I16], &[I32], insert_opcode),
362     (Opcode::Sshr, &[I32, I32], &[I32], insert_opcode),
363     (Opcode::Sshr, &[I32, I64], &[I32], insert_opcode),
364     (Opcode::Sshr, &[I32, I128], &[I32], insert_opcode),
365     (Opcode::Sshr, &[I64, I8], &[I64], insert_opcode),
366     (Opcode::Sshr, &[I64, I16], &[I64], insert_opcode),
367     (Opcode::Sshr, &[I64, I32], &[I64], insert_opcode),
368     (Opcode::Sshr, &[I64, I64], &[I64], insert_opcode),
369     (Opcode::Sshr, &[I64, I128], &[I64], insert_opcode),
370     (Opcode::Sshr, &[I128, I8], &[I128], insert_opcode),
371     (Opcode::Sshr, &[I128, I16], &[I128], insert_opcode),
372     (Opcode::Sshr, &[I128, I32], &[I128], insert_opcode),
373     (Opcode::Sshr, &[I128, I64], &[I128], insert_opcode),
374     (Opcode::Sshr, &[I128, I128], &[I128], insert_opcode),
375     // Ushr
376     (Opcode::Ushr, &[I8, I8], &[I8], insert_opcode),
377     (Opcode::Ushr, &[I8, I16], &[I8], insert_opcode),
378     (Opcode::Ushr, &[I8, I32], &[I8], insert_opcode),
379     (Opcode::Ushr, &[I8, I64], &[I8], insert_opcode),
380     (Opcode::Ushr, &[I8, I128], &[I8], insert_opcode),
381     (Opcode::Ushr, &[I16, I8], &[I16], insert_opcode),
382     (Opcode::Ushr, &[I16, I16], &[I16], insert_opcode),
383     (Opcode::Ushr, &[I16, I32], &[I16], insert_opcode),
384     (Opcode::Ushr, &[I16, I64], &[I16], insert_opcode),
385     (Opcode::Ushr, &[I16, I128], &[I16], insert_opcode),
386     (Opcode::Ushr, &[I32, I8], &[I32], insert_opcode),
387     (Opcode::Ushr, &[I32, I16], &[I32], insert_opcode),
388     (Opcode::Ushr, &[I32, I32], &[I32], insert_opcode),
389     (Opcode::Ushr, &[I32, I64], &[I32], insert_opcode),
390     (Opcode::Ushr, &[I32, I128], &[I32], insert_opcode),
391     (Opcode::Ushr, &[I64, I8], &[I64], insert_opcode),
392     (Opcode::Ushr, &[I64, I16], &[I64], insert_opcode),
393     (Opcode::Ushr, &[I64, I32], &[I64], insert_opcode),
394     (Opcode::Ushr, &[I64, I64], &[I64], insert_opcode),
395     (Opcode::Ushr, &[I64, I128], &[I64], insert_opcode),
396     (Opcode::Ushr, &[I128, I8], &[I128], insert_opcode),
397     (Opcode::Ushr, &[I128, I16], &[I128], insert_opcode),
398     (Opcode::Ushr, &[I128, I32], &[I128], insert_opcode),
399     (Opcode::Ushr, &[I128, I64], &[I128], insert_opcode),
400     (Opcode::Ushr, &[I128, I128], &[I128], insert_opcode),
401     // Uextend
402     (Opcode::Uextend, &[I8], &[I16], insert_opcode),
403     (Opcode::Uextend, &[I8], &[I32], insert_opcode),
404     (Opcode::Uextend, &[I8], &[I64], insert_opcode),
405     (Opcode::Uextend, &[I8], &[I128], insert_opcode),
406     (Opcode::Uextend, &[I16], &[I32], insert_opcode),
407     (Opcode::Uextend, &[I16], &[I64], insert_opcode),
408     (Opcode::Uextend, &[I16], &[I128], insert_opcode),
409     (Opcode::Uextend, &[I32], &[I64], insert_opcode),
410     (Opcode::Uextend, &[I32], &[I128], insert_opcode),
411     (Opcode::Uextend, &[I64], &[I128], insert_opcode),
412     // Sextend
413     (Opcode::Sextend, &[I8], &[I16], insert_opcode),
414     (Opcode::Sextend, &[I8], &[I32], insert_opcode),
415     (Opcode::Sextend, &[I8], &[I64], insert_opcode),
416     (Opcode::Sextend, &[I8], &[I128], insert_opcode),
417     (Opcode::Sextend, &[I16], &[I32], insert_opcode),
418     (Opcode::Sextend, &[I16], &[I64], insert_opcode),
419     (Opcode::Sextend, &[I16], &[I128], insert_opcode),
420     (Opcode::Sextend, &[I32], &[I64], insert_opcode),
421     (Opcode::Sextend, &[I32], &[I128], insert_opcode),
422     (Opcode::Sextend, &[I64], &[I128], insert_opcode),
423     // Ireduce
424     (Opcode::Ireduce, &[I16], &[I8], insert_opcode),
425     (Opcode::Ireduce, &[I32], &[I8], insert_opcode),
426     (Opcode::Ireduce, &[I32], &[I16], insert_opcode),
427     (Opcode::Ireduce, &[I64], &[I8], insert_opcode),
428     (Opcode::Ireduce, &[I64], &[I16], insert_opcode),
429     (Opcode::Ireduce, &[I64], &[I32], insert_opcode),
430     (Opcode::Ireduce, &[I128], &[I8], insert_opcode),
431     (Opcode::Ireduce, &[I128], &[I16], insert_opcode),
432     (Opcode::Ireduce, &[I128], &[I32], insert_opcode),
433     (Opcode::Ireduce, &[I128], &[I64], insert_opcode),
434     // Isplit
435     (Opcode::Isplit, &[I128], &[I64, I64], insert_opcode),
436     // Iconcat
437     (Opcode::Iconcat, &[I64, I64], &[I128], insert_opcode),
438     // Fadd
439     (Opcode::Fadd, &[F32, F32], &[F32], insert_opcode),
440     (Opcode::Fadd, &[F64, F64], &[F64], insert_opcode),
441     // Fmul
442     (Opcode::Fmul, &[F32, F32], &[F32], insert_opcode),
443     (Opcode::Fmul, &[F64, F64], &[F64], insert_opcode),
444     // Fsub
445     (Opcode::Fsub, &[F32, F32], &[F32], insert_opcode),
446     (Opcode::Fsub, &[F64, F64], &[F64], insert_opcode),
447     // Fdiv
448     (Opcode::Fdiv, &[F32, F32], &[F32], insert_opcode),
449     (Opcode::Fdiv, &[F64, F64], &[F64], insert_opcode),
450     // Fmin
451     (Opcode::Fmin, &[F32, F32], &[F32], insert_opcode),
452     (Opcode::Fmin, &[F64, F64], &[F64], insert_opcode),
453     // Fmax
454     (Opcode::Fmax, &[F32, F32], &[F32], insert_opcode),
455     (Opcode::Fmax, &[F64, F64], &[F64], insert_opcode),
456     // FminPseudo
457     (Opcode::FminPseudo, &[F32, F32], &[F32], insert_opcode),
458     (Opcode::FminPseudo, &[F64, F64], &[F64], insert_opcode),
459     // FmaxPseudo
460     (Opcode::FmaxPseudo, &[F32, F32], &[F32], insert_opcode),
461     (Opcode::FmaxPseudo, &[F64, F64], &[F64], insert_opcode),
462     // Fcopysign
463     (Opcode::Fcopysign, &[F32, F32], &[F32], insert_opcode),
464     (Opcode::Fcopysign, &[F64, F64], &[F64], insert_opcode),
465     // Fma
466     (Opcode::Fma, &[F32, F32, F32], &[F32], insert_opcode),
467     (Opcode::Fma, &[F64, F64, F64], &[F64], insert_opcode),
468     // Fabs
469     (Opcode::Fabs, &[F32], &[F32], insert_opcode),
470     (Opcode::Fabs, &[F64], &[F64], insert_opcode),
471     // Fneg
472     (Opcode::Fneg, &[F32], &[F32], insert_opcode),
473     (Opcode::Fneg, &[F64], &[F64], insert_opcode),
474     // Sqrt
475     (Opcode::Sqrt, &[F32], &[F32], insert_opcode),
476     (Opcode::Sqrt, &[F64], &[F64], insert_opcode),
477     // Ceil
478     (Opcode::Ceil, &[F32], &[F32], insert_opcode),
479     (Opcode::Ceil, &[F64], &[F64], insert_opcode),
480     // Floor
481     (Opcode::Floor, &[F32], &[F32], insert_opcode),
482     (Opcode::Floor, &[F64], &[F64], insert_opcode),
483     // Trunc
484     (Opcode::Trunc, &[F32], &[F32], insert_opcode),
485     (Opcode::Trunc, &[F64], &[F64], insert_opcode),
486     // Nearest
487     (Opcode::Nearest, &[F32], &[F32], insert_opcode),
488     (Opcode::Nearest, &[F64], &[F64], insert_opcode),
489     // FcvtToUint
490     // TODO: Some ops disabled:
491     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4897
492     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4899
493     //   aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934
494     #[cfg(not(target_arch = "x86_64"))]
495     (Opcode::FcvtToUint, &[F32], &[I8], insert_opcode),
496     #[cfg(not(target_arch = "x86_64"))]
497     (Opcode::FcvtToUint, &[F32], &[I16], insert_opcode),
498     (Opcode::FcvtToUint, &[F32], &[I32], insert_opcode),
499     (Opcode::FcvtToUint, &[F32], &[I64], insert_opcode),
500     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
501     (Opcode::FcvtToUint, &[F32], &[I128], insert_opcode),
502     #[cfg(not(target_arch = "x86_64"))]
503     (Opcode::FcvtToUint, &[F64], &[I8], insert_opcode),
504     #[cfg(not(target_arch = "x86_64"))]
505     (Opcode::FcvtToUint, &[F64], &[I16], insert_opcode),
506     (Opcode::FcvtToUint, &[F64], &[I32], insert_opcode),
507     (Opcode::FcvtToUint, &[F64], &[I64], insert_opcode),
508     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
509     (Opcode::FcvtToUint, &[F64], &[I128], insert_opcode),
510     // FcvtToUintSat
511     // TODO: Some ops disabled:
512     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4897
513     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4899
514     //   aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934
515     #[cfg(not(target_arch = "x86_64"))]
516     (Opcode::FcvtToUintSat, &[F32], &[I8], insert_opcode),
517     #[cfg(not(target_arch = "x86_64"))]
518     (Opcode::FcvtToUintSat, &[F32], &[I16], insert_opcode),
519     (Opcode::FcvtToUintSat, &[F32], &[I32], insert_opcode),
520     (Opcode::FcvtToUintSat, &[F32], &[I64], insert_opcode),
521     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
522     (Opcode::FcvtToUintSat, &[F32], &[I128], insert_opcode),
523     #[cfg(not(target_arch = "x86_64"))]
524     (Opcode::FcvtToUintSat, &[F64], &[I8], insert_opcode),
525     #[cfg(not(target_arch = "x86_64"))]
526     (Opcode::FcvtToUintSat, &[F64], &[I16], insert_opcode),
527     (Opcode::FcvtToUintSat, &[F64], &[I32], insert_opcode),
528     (Opcode::FcvtToUintSat, &[F64], &[I64], insert_opcode),
529     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
530     (Opcode::FcvtToUintSat, &[F64], &[I128], insert_opcode),
531     // FcvtToSint
532     // TODO: Some ops disabled:
533     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4897
534     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4899
535     //   aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934
536     #[cfg(not(target_arch = "x86_64"))]
537     (Opcode::FcvtToSint, &[F32], &[I8], insert_opcode),
538     #[cfg(not(target_arch = "x86_64"))]
539     (Opcode::FcvtToSint, &[F32], &[I16], insert_opcode),
540     (Opcode::FcvtToSint, &[F32], &[I32], insert_opcode),
541     (Opcode::FcvtToSint, &[F32], &[I64], insert_opcode),
542     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
543     (Opcode::FcvtToSint, &[F32], &[I128], insert_opcode),
544     #[cfg(not(target_arch = "x86_64"))]
545     (Opcode::FcvtToSint, &[F64], &[I8], insert_opcode),
546     #[cfg(not(target_arch = "x86_64"))]
547     (Opcode::FcvtToSint, &[F64], &[I16], insert_opcode),
548     (Opcode::FcvtToSint, &[F64], &[I32], insert_opcode),
549     (Opcode::FcvtToSint, &[F64], &[I64], insert_opcode),
550     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
551     (Opcode::FcvtToSint, &[F64], &[I128], insert_opcode),
552     // FcvtToSintSat
553     // TODO: Some ops disabled:
554     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4897
555     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4899
556     //   aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934
557     #[cfg(not(target_arch = "x86_64"))]
558     (Opcode::FcvtToSintSat, &[F32], &[I8], insert_opcode),
559     #[cfg(not(target_arch = "x86_64"))]
560     (Opcode::FcvtToSintSat, &[F32], &[I16], insert_opcode),
561     (Opcode::FcvtToSintSat, &[F32], &[I32], insert_opcode),
562     (Opcode::FcvtToSintSat, &[F32], &[I64], insert_opcode),
563     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
564     (Opcode::FcvtToSintSat, &[F32], &[I128], insert_opcode),
565     #[cfg(not(target_arch = "x86_64"))]
566     (Opcode::FcvtToSintSat, &[F64], &[I8], insert_opcode),
567     #[cfg(not(target_arch = "x86_64"))]
568     (Opcode::FcvtToSintSat, &[F64], &[I16], insert_opcode),
569     (Opcode::FcvtToSintSat, &[F64], &[I32], insert_opcode),
570     (Opcode::FcvtToSintSat, &[F64], &[I64], insert_opcode),
571     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
572     (Opcode::FcvtToSintSat, &[F64], &[I128], insert_opcode),
573     // FcvtFromUint
574     // TODO: Some ops disabled:
575     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4900
576     //   aarch64: https://github.com/bytecodealliance/wasmtime/issues/4933
577     (Opcode::FcvtFromUint, &[I8], &[F32], insert_opcode),
578     (Opcode::FcvtFromUint, &[I16], &[F32], insert_opcode),
579     (Opcode::FcvtFromUint, &[I32], &[F32], insert_opcode),
580     (Opcode::FcvtFromUint, &[I64], &[F32], insert_opcode),
581     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
582     (Opcode::FcvtFromUint, &[I128], &[F32], insert_opcode),
583     (Opcode::FcvtFromUint, &[I8], &[F64], insert_opcode),
584     (Opcode::FcvtFromUint, &[I16], &[F64], insert_opcode),
585     (Opcode::FcvtFromUint, &[I32], &[F64], insert_opcode),
586     (Opcode::FcvtFromUint, &[I64], &[F64], insert_opcode),
587     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
588     (Opcode::FcvtFromUint, &[I128], &[F64], insert_opcode),
589     // FcvtFromSint
590     // TODO: Some ops disabled:
591     //   x64: https://github.com/bytecodealliance/wasmtime/issues/4900
592     //   aarch64: https://github.com/bytecodealliance/wasmtime/issues/4933
593     (Opcode::FcvtFromSint, &[I8], &[F32], insert_opcode),
594     (Opcode::FcvtFromSint, &[I16], &[F32], insert_opcode),
595     (Opcode::FcvtFromSint, &[I32], &[F32], insert_opcode),
596     (Opcode::FcvtFromSint, &[I64], &[F32], insert_opcode),
597     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
598     (Opcode::FcvtFromSint, &[I128], &[F32], insert_opcode),
599     (Opcode::FcvtFromSint, &[I8], &[F64], insert_opcode),
600     (Opcode::FcvtFromSint, &[I16], &[F64], insert_opcode),
601     (Opcode::FcvtFromSint, &[I32], &[F64], insert_opcode),
602     (Opcode::FcvtFromSint, &[I64], &[F64], insert_opcode),
603     #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
604     (Opcode::FcvtFromSint, &[I128], &[F64], insert_opcode),
605     // Fcmp
606     (Opcode::Fcmp, &[F32, F32], &[B1], insert_cmp),
607     (Opcode::Fcmp, &[F64, F64], &[B1], insert_cmp),
608     // Icmp
609     (Opcode::Icmp, &[I8, I8], &[B1], insert_cmp),
610     (Opcode::Icmp, &[I16, I16], &[B1], insert_cmp),
611     (Opcode::Icmp, &[I32, I32], &[B1], insert_cmp),
612     (Opcode::Icmp, &[I64, I64], &[B1], insert_cmp),
613     (Opcode::Icmp, &[I128, I128], &[B1], insert_cmp),
614     // Stack Access
615     (Opcode::StackStore, &[I8], &[], insert_stack_store),
616     (Opcode::StackStore, &[I16], &[], insert_stack_store),
617     (Opcode::StackStore, &[I32], &[], insert_stack_store),
618     (Opcode::StackStore, &[I64], &[], insert_stack_store),
619     (Opcode::StackStore, &[I128], &[], insert_stack_store),
620     (Opcode::StackLoad, &[], &[I8], insert_stack_load),
621     (Opcode::StackLoad, &[], &[I16], insert_stack_load),
622     (Opcode::StackLoad, &[], &[I32], insert_stack_load),
623     (Opcode::StackLoad, &[], &[I64], insert_stack_load),
624     (Opcode::StackLoad, &[], &[I128], insert_stack_load),
625     // Loads
626     (Opcode::Load, &[], &[I8], insert_load_store),
627     (Opcode::Load, &[], &[I16], insert_load_store),
628     (Opcode::Load, &[], &[I32], insert_load_store),
629     (Opcode::Load, &[], &[I64], insert_load_store),
630     (Opcode::Load, &[], &[I128], insert_load_store),
631     (Opcode::Load, &[], &[F32], insert_load_store),
632     (Opcode::Load, &[], &[F64], insert_load_store),
633     // Special Loads
634     (Opcode::Uload8, &[], &[I16], insert_load_store),
635     (Opcode::Uload8, &[], &[I32], insert_load_store),
636     (Opcode::Uload8, &[], &[I64], insert_load_store),
637     (Opcode::Uload16, &[], &[I32], insert_load_store),
638     (Opcode::Uload16, &[], &[I64], insert_load_store),
639     (Opcode::Uload32, &[], &[I64], insert_load_store),
640     (Opcode::Sload8, &[], &[I16], insert_load_store),
641     (Opcode::Sload8, &[], &[I32], insert_load_store),
642     (Opcode::Sload8, &[], &[I64], insert_load_store),
643     (Opcode::Sload16, &[], &[I32], insert_load_store),
644     (Opcode::Sload16, &[], &[I64], insert_load_store),
645     (Opcode::Sload32, &[], &[I64], insert_load_store),
646     // TODO: Unimplemented in the interpreter
647     // Opcode::Uload8x8
648     // Opcode::Sload8x8
649     // Opcode::Uload16x4
650     // Opcode::Sload16x4
651     // Opcode::Uload32x2
652     // Opcode::Sload32x2
653     // Stores
654     (Opcode::Store, &[I8], &[], insert_load_store),
655     (Opcode::Store, &[I16], &[], insert_load_store),
656     (Opcode::Store, &[I32], &[], insert_load_store),
657     (Opcode::Store, &[I64], &[], insert_load_store),
658     (Opcode::Store, &[I128], &[], insert_load_store),
659     (Opcode::Store, &[F32], &[], insert_load_store),
660     (Opcode::Store, &[F64], &[], insert_load_store),
661     // Special Stores
662     (Opcode::Istore8, &[I16], &[], insert_load_store),
663     (Opcode::Istore8, &[I32], &[], insert_load_store),
664     (Opcode::Istore8, &[I64], &[], insert_load_store),
665     (Opcode::Istore16, &[I32], &[], insert_load_store),
666     (Opcode::Istore16, &[I64], &[], insert_load_store),
667     (Opcode::Istore32, &[I64], &[], insert_load_store),
668     // Integer Consts
669     (Opcode::Iconst, &[], &[I8], insert_const),
670     (Opcode::Iconst, &[], &[I16], insert_const),
671     (Opcode::Iconst, &[], &[I32], insert_const),
672     (Opcode::Iconst, &[], &[I64], insert_const),
673     (Opcode::Iconst, &[], &[I128], insert_const),
674     // Float Consts
675     (Opcode::F32const, &[], &[F32], insert_const),
676     (Opcode::F64const, &[], &[F64], insert_const),
677     // Bool Consts
678     (Opcode::Bconst, &[], &[B1], insert_const),
679     // Call
680     (Opcode::Call, &[], &[], insert_call),
681 ];
682 
683 type BlockTerminator = fn(
684     fgen: &mut FunctionGenerator,
685     builder: &mut FunctionBuilder,
686     source_block: Block,
687 ) -> Result<()>;
688 
689 fn insert_return(
690     fgen: &mut FunctionGenerator,
691     builder: &mut FunctionBuilder,
692     _source_block: Block,
693 ) -> Result<()> {
694     let types: Vec<Type> = {
695         let rets = &builder.func.signature.returns;
696         rets.iter().map(|p| p.value_type).collect()
697     };
698     let vals = fgen.generate_values_for_signature(builder, types.into_iter())?;
699 
700     builder.ins().return_(&vals[..]);
701     Ok(())
702 }
703 
704 fn insert_jump(
705     fgen: &mut FunctionGenerator,
706     builder: &mut FunctionBuilder,
707     source_block: Block,
708 ) -> Result<()> {
709     let (block, args) = fgen.generate_target_block(builder, source_block)?;
710     builder.ins().jump(block, &args[..]);
711     Ok(())
712 }
713 
714 /// Generates a br_table into a random block
715 fn insert_br_table(
716     fgen: &mut FunctionGenerator,
717     builder: &mut FunctionBuilder,
718     source_block: Block,
719 ) -> Result<()> {
720     let var = fgen.get_variable_of_type(I32)?; // br_table only supports I32
721     let val = builder.use_var(var);
722 
723     let target_blocks = fgen.resources.forward_blocks_without_params(source_block);
724     let default_block = *fgen.u.choose(target_blocks)?;
725 
726     // We can still select a backwards branching jump table here!
727     let tables = fgen.resources.forward_jump_tables(builder, source_block);
728     let jt = *fgen.u.choose(&tables[..])?;
729     builder.ins().br_table(val, default_block, jt);
730     Ok(())
731 }
732 
733 /// Generates a brz/brnz into a random block
734 fn insert_br(
735     fgen: &mut FunctionGenerator,
736     builder: &mut FunctionBuilder,
737     source_block: Block,
738 ) -> Result<()> {
739     let (block, args) = fgen.generate_target_block(builder, source_block)?;
740 
741     let condbr_types = [I8, I16, I32, I64, I128, B1];
742     let _type = *fgen.u.choose(&condbr_types[..])?;
743     let var = fgen.get_variable_of_type(_type)?;
744     let val = builder.use_var(var);
745 
746     if bool::arbitrary(fgen.u)? {
747         builder.ins().brz(val, block, &args[..]);
748     } else {
749         builder.ins().brnz(val, block, &args[..]);
750     }
751 
752     // After brz/brnz we must generate a jump
753     insert_jump(fgen, builder, source_block)?;
754     Ok(())
755 }
756 
757 fn insert_bricmp(
758     fgen: &mut FunctionGenerator,
759     builder: &mut FunctionBuilder,
760     source_block: Block,
761 ) -> Result<()> {
762     let (block, args) = fgen.generate_target_block(builder, source_block)?;
763 
764     let cc = *fgen.u.choose(IntCC::all())?;
765     let _type = *fgen.u.choose(&[I8, I16, I32, I64, I128])?;
766 
767     let lhs_var = fgen.get_variable_of_type(_type)?;
768     let lhs_val = builder.use_var(lhs_var);
769 
770     let rhs_var = fgen.get_variable_of_type(_type)?;
771     let rhs_val = builder.use_var(rhs_var);
772 
773     builder
774         .ins()
775         .br_icmp(cc, lhs_val, rhs_val, block, &args[..]);
776 
777     // After bricmp's we must generate a jump
778     insert_jump(fgen, builder, source_block)?;
779     Ok(())
780 }
781 
782 fn insert_switch(
783     fgen: &mut FunctionGenerator,
784     builder: &mut FunctionBuilder,
785     source_block: Block,
786 ) -> Result<()> {
787     let _type = *fgen.u.choose(&[I8, I16, I32, I64, I128][..])?;
788     let switch_var = fgen.get_variable_of_type(_type)?;
789     let switch_val = builder.use_var(switch_var);
790 
791     // TODO: We should also generate backwards branches in switches
792     let default_block = {
793         let target_blocks = fgen.resources.forward_blocks_without_params(source_block);
794         *fgen.u.choose(target_blocks)?
795     };
796 
797     // Build this into a HashMap since we cannot have duplicate entries.
798     let mut entries = HashMap::new();
799     for _ in 0..fgen.param(&fgen.config.switch_cases)? {
800         // The Switch API only allows for entries that are addressable by the index type
801         // so we need to limit the range of values that we generate.
802         let (ty_min, ty_max) = _type.bounds(false);
803         let range_start = fgen.u.int_in_range(ty_min..=ty_max)?;
804 
805         // We can either insert a contiguous range of blocks or a individual block
806         // This is done because the Switch API specializes contiguous ranges.
807         let range_size = if bool::arbitrary(fgen.u)? {
808             1
809         } else {
810             fgen.param(&fgen.config.switch_max_range_size)?
811         } as u128;
812 
813         // Build the switch entries
814         for i in 0..range_size {
815             let index = range_start.wrapping_add(i) % ty_max;
816             let block = {
817                 let target_blocks = fgen.resources.forward_blocks_without_params(source_block);
818                 *fgen.u.choose(target_blocks)?
819             };
820 
821             entries.insert(index, block);
822         }
823     }
824 
825     let mut switch = Switch::new();
826     for (entry, block) in entries.into_iter() {
827         switch.set_entry(entry, block);
828     }
829     switch.emit(builder, switch_val, default_block);
830 
831     Ok(())
832 }
833 
834 /// These libcalls need a interpreter implementation in `cranelift-fuzzgen.rs`
835 const ALLOWED_LIBCALLS: &'static [LibCall] = &[
836     LibCall::CeilF32,
837     LibCall::CeilF64,
838     LibCall::FloorF32,
839     LibCall::FloorF64,
840     LibCall::TruncF32,
841     LibCall::TruncF64,
842 ];
843 
844 pub struct FunctionGenerator<'r, 'data>
845 where
846     'data: 'r,
847 {
848     u: &'r mut Unstructured<'data>,
849     config: &'r Config,
850     resources: Resources,
851 }
852 
853 #[derive(Default)]
854 struct Resources {
855     vars: HashMap<Type, Vec<Variable>>,
856     blocks: Vec<(Block, BlockSignature)>,
857     blocks_without_params: Vec<Block>,
858     jump_tables: Vec<JumpTable>,
859     func_refs: Vec<(Signature, FuncRef)>,
860     stack_slots: Vec<(StackSlot, StackSize)>,
861 }
862 
863 impl Resources {
864     /// Returns [JumpTable]'s where all blocks are forward of `block`
865     fn forward_jump_tables(&self, builder: &FunctionBuilder, block: Block) -> Vec<JumpTable> {
866         // TODO: We can avoid allocating a Vec here by sorting self.jump_tables based
867         // on the minimum block and returning a slice based on that.
868         // See https://github.com/bytecodealliance/wasmtime/pull/4894#discussion_r971241430 for more details
869 
870         // Unlike with the blocks below jump table targets are not ordered, thus we do need
871         // to allocate a Vec here.
872         let jump_tables = &builder.func.jump_tables;
873         self.jump_tables
874             .iter()
875             .copied()
876             .filter(|jt| jump_tables[*jt].iter().all(|target| *target > block))
877             .collect()
878     }
879 
880     /// Partitions blocks at `block`. Only blocks that can be targeted by branches are considered.
881     ///
882     /// The first slice includes all blocks up to and including `block`.
883     /// The second slice includes all remaining blocks.
884     fn partition_target_blocks(
885         &self,
886         block: Block,
887     ) -> (&[(Block, BlockSignature)], &[(Block, BlockSignature)]) {
888         // Blocks are stored in-order and have no gaps, this means that we can simply index them by
889         // their number. We also need to exclude the entry block since it isn't a valid target.
890         let target_blocks = &self.blocks[1..];
891         target_blocks.split_at(block.as_u32() as usize)
892     }
893 
894     /// Generates a slice of `blocks_without_params` ahead of `block`
895     fn forward_blocks_without_params(&self, block: Block) -> &[Block] {
896         let partition_point = self.blocks_without_params.partition_point(|b| *b <= block);
897         &self.blocks_without_params[partition_point..]
898     }
899 }
900 
901 impl<'r, 'data> FunctionGenerator<'r, 'data>
902 where
903     'data: 'r,
904 {
905     pub fn new(u: &'r mut Unstructured<'data>, config: &'r Config) -> Self {
906         Self {
907             u,
908             config,
909             resources: Resources::default(),
910         }
911     }
912 
913     /// Generates a random value for config `param`
914     fn param(&mut self, param: &RangeInclusive<usize>) -> Result<usize> {
915         Ok(self.u.int_in_range(param.clone())?)
916     }
917 
918     fn generate_callconv(&mut self) -> Result<CallConv> {
919         // TODO: Generate random CallConvs per target
920         Ok(CallConv::SystemV)
921     }
922 
923     fn system_callconv(&mut self) -> CallConv {
924         // TODO: This currently only runs on linux, so this is the only choice
925         // We should improve this once we generate flags and targets
926         CallConv::SystemV
927     }
928 
929     fn generate_type(&mut self) -> Result<Type> {
930         // TODO: It would be nice if we could get these directly from cranelift
931         let scalars = [
932             // IFLAGS, FFLAGS,
933             B1, // B8, B16, B32, B64, B128,
934             I8, I16, I32, I64, I128, F32, F64,
935             // R32, R64,
936         ];
937         // TODO: vector types
938 
939         let ty = self.u.choose(&scalars[..])?;
940         Ok(*ty)
941     }
942 
943     fn generate_abi_param(&mut self) -> Result<AbiParam> {
944         let value_type = self.generate_type()?;
945         // TODO: There are more argument purposes to be explored...
946         let purpose = ArgumentPurpose::Normal;
947         let extension = match self.u.int_in_range(0..=2)? {
948             2 => ArgumentExtension::Sext,
949             1 => ArgumentExtension::Uext,
950             _ => ArgumentExtension::None,
951         };
952 
953         Ok(AbiParam {
954             value_type,
955             purpose,
956             extension,
957         })
958     }
959 
960     fn generate_signature(&mut self) -> Result<Signature> {
961         let callconv = self.generate_callconv()?;
962         let mut sig = Signature::new(callconv);
963 
964         for _ in 0..self.param(&self.config.signature_params)? {
965             sig.params.push(self.generate_abi_param()?);
966         }
967 
968         for _ in 0..self.param(&self.config.signature_rets)? {
969             sig.returns.push(self.generate_abi_param()?);
970         }
971 
972         Ok(sig)
973     }
974 
975     /// Finds a stack slot with size of at least n bytes
976     fn stack_slot_with_size(&mut self, n: u32) -> Result<(StackSlot, StackSize)> {
977         let first = self
978             .resources
979             .stack_slots
980             .partition_point(|&(_slot, size)| size < n);
981         Ok(*self.u.choose(&self.resources.stack_slots[first..])?)
982     }
983 
984     /// Generates an address that should allow for a store or a load.
985     ///
986     /// Addresses aren't generated like other values. They are never stored in variables so that
987     /// we don't run the risk of returning them from a function, which would make the fuzzer
988     /// complain since they are different from the interpreter to the backend.
989     ///
990     /// The address is not guaranteed to be valid, but there's a chance that it is.
991     ///
992     /// `min_size`: Controls the amount of space that the address should have.This is not
993     /// guaranteed to be respected
994     fn generate_load_store_address(
995         &mut self,
996         builder: &mut FunctionBuilder,
997         min_size: u32,
998     ) -> Result<(Value, Offset32)> {
999         // TODO: Currently our only source of addresses is stack_addr, but we should
1000         // add heap_addr, global_value, symbol_value eventually
1001         let (addr, available_size) = {
1002             let (ss, slot_size) = self.stack_slot_with_size(min_size)?;
1003             let max_offset = slot_size.saturating_sub(min_size);
1004             let offset = self.u.int_in_range(0..=max_offset)? as i32;
1005             let base_addr = builder.ins().stack_addr(I64, ss, offset);
1006             let available_size = (slot_size as i32).saturating_sub(offset);
1007             (base_addr, available_size)
1008         };
1009 
1010         // TODO: Insert a bunch of amode opcodes here to modify the address!
1011 
1012         // Now that we have an address and a size, we just choose a random offset to return to the
1013         // caller. Try to preserve min_size bytes.
1014         let max_offset = available_size.saturating_sub(min_size as i32);
1015         let offset = self.u.int_in_range(0..=max_offset)? as i32;
1016 
1017         Ok((addr, offset.into()))
1018     }
1019 
1020     /// Get a variable of type `ty` from the current function
1021     fn get_variable_of_type(&mut self, ty: Type) -> Result<Variable> {
1022         let opts = self.resources.vars.get(&ty).map_or(&[][..], Vec::as_slice);
1023         let var = self.u.choose(opts)?;
1024         Ok(*var)
1025     }
1026 
1027     /// Generates an instruction(`iconst`/`fconst`/etc...) to introduce a constant value
1028     fn generate_const(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Value> {
1029         Ok(match ty {
1030             I128 => {
1031                 // See: https://github.com/bytecodealliance/wasmtime/issues/2906
1032                 let hi = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?);
1033                 let lo = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?);
1034                 builder.ins().iconcat(lo, hi)
1035             }
1036             ty if ty.is_int() => {
1037                 let imm64 = match ty {
1038                     I8 => self.u.arbitrary::<i8>()? as i64,
1039                     I16 => self.u.arbitrary::<i16>()? as i64,
1040                     I32 => self.u.arbitrary::<i32>()? as i64,
1041                     I64 => self.u.arbitrary::<i64>()?,
1042                     _ => unreachable!(),
1043                 };
1044                 builder.ins().iconst(ty, imm64)
1045             }
1046             ty if ty.is_bool() => builder.ins().bconst(ty, bool::arbitrary(self.u)?),
1047             // f{32,64}::arbitrary does not generate a bunch of important values
1048             // such as Signaling NaN's / NaN's with payload, so generate floats from integers.
1049             F32 => builder
1050                 .ins()
1051                 .f32const(f32::from_bits(u32::arbitrary(self.u)?)),
1052             F64 => builder
1053                 .ins()
1054                 .f64const(f64::from_bits(u64::arbitrary(self.u)?)),
1055             _ => unimplemented!(),
1056         })
1057     }
1058 
1059     /// Chooses a random block which can be targeted by a jump / branch.
1060     /// This means any block that is not the first block.
1061     ///
1062     /// For convenience we also generate values that match the block's signature
1063     fn generate_target_block(
1064         &mut self,
1065         builder: &mut FunctionBuilder,
1066         source_block: Block,
1067     ) -> Result<(Block, Vec<Value>)> {
1068         // We try to mostly generate forward branches to avoid generating an excessive amount of
1069         // infinite loops. But they are still important, so give them a small chance of existing.
1070         let (backwards_blocks, forward_blocks) =
1071             self.resources.partition_target_blocks(source_block);
1072         let ratio = self.config.backwards_branch_ratio;
1073         let block_targets = if !backwards_blocks.is_empty() && self.u.ratio(ratio.0, ratio.1)? {
1074             backwards_blocks
1075         } else {
1076             forward_blocks
1077         };
1078         assert!(!block_targets.is_empty());
1079 
1080         let (block, signature) = self.u.choose(block_targets)?.clone();
1081         let args = self.generate_values_for_signature(builder, signature.into_iter())?;
1082         Ok((block, args))
1083     }
1084 
1085     fn generate_values_for_signature<I: Iterator<Item = Type>>(
1086         &mut self,
1087         builder: &mut FunctionBuilder,
1088         signature: I,
1089     ) -> Result<Vec<Value>> {
1090         signature
1091             .map(|ty| {
1092                 let var = self.get_variable_of_type(ty)?;
1093                 let val = builder.use_var(var);
1094                 Ok(val)
1095             })
1096             .collect()
1097     }
1098 
1099     /// We always need to exit safely out of a block.
1100     /// This either means a jump into another block or a return.
1101     fn finalize_block(&mut self, builder: &mut FunctionBuilder, source_block: Block) -> Result<()> {
1102         let has_jump_tables = !self
1103             .resources
1104             .forward_jump_tables(builder, source_block)
1105             .is_empty();
1106 
1107         let has_forward_blocks = {
1108             let (_, forward_blocks) = self.resources.partition_target_blocks(source_block);
1109             !forward_blocks.is_empty()
1110         };
1111 
1112         let has_forward_blocks_without_params = !self
1113             .resources
1114             .forward_blocks_without_params(source_block)
1115             .is_empty();
1116 
1117         let terminators: &[(BlockTerminator, bool)] = &[
1118             // Return is always a valid option
1119             (insert_return, true),
1120             // If we have forward blocks, we can allow generating jumps and branches
1121             (insert_jump, has_forward_blocks),
1122             (insert_br, has_forward_blocks),
1123             (insert_bricmp, has_forward_blocks),
1124             // Switches can only use blocks without params
1125             (insert_switch, has_forward_blocks_without_params),
1126             // We need both jump tables and a default block for br_table
1127             (
1128                 insert_br_table,
1129                 has_jump_tables && has_forward_blocks_without_params,
1130             ),
1131         ];
1132 
1133         let terminators: Vec<_> = terminators
1134             .into_iter()
1135             .filter(|(_, valid)| *valid)
1136             .map(|(term, _)| term)
1137             .collect();
1138 
1139         let inserter = self.u.choose(&terminators[..])?;
1140         inserter(self, builder, source_block)?;
1141 
1142         Ok(())
1143     }
1144 
1145     /// Fills the current block with random instructions
1146     fn generate_instructions(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1147         for _ in 0..self.param(&self.config.instructions_per_block)? {
1148             let (op, args, rets, inserter) = *self.u.choose(OPCODE_SIGNATURES)?;
1149             inserter(self, builder, op, args, rets)?;
1150         }
1151 
1152         Ok(())
1153     }
1154 
1155     fn generate_jumptables(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1156         // We shouldn't try to generate jumptables if we don't have any valid targets!
1157         if self.resources.blocks_without_params.is_empty() {
1158             return Ok(());
1159         }
1160 
1161         for _ in 0..self.param(&self.config.jump_tables_per_function)? {
1162             let mut jt_data = JumpTableData::new();
1163 
1164             for _ in 0..self.param(&self.config.jump_table_entries)? {
1165                 let block = *self.u.choose(&self.resources.blocks_without_params)?;
1166                 jt_data.push_entry(block);
1167             }
1168 
1169             self.resources
1170                 .jump_tables
1171                 .push(builder.create_jump_table(jt_data));
1172         }
1173         Ok(())
1174     }
1175 
1176     fn generate_funcrefs(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1177         let count = self.param(&self.config.funcrefs_per_function)?;
1178         for func_index in 0..count.try_into().unwrap() {
1179             let (ext_name, sig) = if self.u.arbitrary::<bool>()? {
1180                 let user_func_ref = builder
1181                     .func
1182                     .declare_imported_user_function(UserExternalName {
1183                         namespace: 0,
1184                         index: func_index,
1185                     });
1186                 let name = ExternalName::User(user_func_ref);
1187                 let signature = self.generate_signature()?;
1188                 (name, signature)
1189             } else {
1190                 let libcall = *self.u.choose(ALLOWED_LIBCALLS)?;
1191                 // TODO: Use [CallConv::for_libcall] once we generate flags.
1192                 let callconv = self.system_callconv();
1193                 let signature = libcall.signature(callconv);
1194                 (ExternalName::LibCall(libcall), signature)
1195             };
1196 
1197             let sig_ref = builder.import_signature(sig.clone());
1198             let func_ref = builder.import_function(ExtFuncData {
1199                 name: ext_name,
1200                 signature: sig_ref,
1201                 colocated: self.u.arbitrary()?,
1202             });
1203 
1204             self.resources.func_refs.push((sig, func_ref));
1205         }
1206 
1207         Ok(())
1208     }
1209 
1210     fn generate_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1211         for _ in 0..self.param(&self.config.static_stack_slots_per_function)? {
1212             let bytes = self.param(&self.config.static_stack_slot_size)? as u32;
1213             let ss_data = StackSlotData::new(StackSlotKind::ExplicitSlot, bytes);
1214             let slot = builder.create_sized_stack_slot(ss_data);
1215             self.resources.stack_slots.push((slot, bytes));
1216         }
1217 
1218         self.resources
1219             .stack_slots
1220             .sort_unstable_by_key(|&(_slot, bytes)| bytes);
1221 
1222         Ok(())
1223     }
1224 
1225     /// Zero initializes the stack slot by inserting `stack_store`'s.
1226     fn initialize_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1227         let i128_zero = builder.ins().iconst(I128, 0);
1228         let i64_zero = builder.ins().iconst(I64, 0);
1229         let i32_zero = builder.ins().iconst(I32, 0);
1230         let i16_zero = builder.ins().iconst(I16, 0);
1231         let i8_zero = builder.ins().iconst(I8, 0);
1232 
1233         for &(slot, init_size) in self.resources.stack_slots.iter() {
1234             let mut size = init_size;
1235 
1236             // Insert the largest available store for the remaining size.
1237             while size != 0 {
1238                 let offset = (init_size - size) as i32;
1239                 let (val, filled) = match size {
1240                     sz if sz / 16 > 0 => (i128_zero, 16),
1241                     sz if sz / 8 > 0 => (i64_zero, 8),
1242                     sz if sz / 4 > 0 => (i32_zero, 4),
1243                     sz if sz / 2 > 0 => (i16_zero, 2),
1244                     _ => (i8_zero, 1),
1245                 };
1246                 builder.ins().stack_store(val, slot, offset);
1247                 size -= filled;
1248             }
1249         }
1250         Ok(())
1251     }
1252 
1253     /// Creates a random amount of blocks in this function
1254     fn generate_blocks(&mut self, builder: &mut FunctionBuilder, sig: &Signature) -> Result<()> {
1255         let extra_block_count = self.param(&self.config.blocks_per_function)?;
1256 
1257         // We must always have at least one block, so we generate the "extra" blocks and add 1 for
1258         // the entry block.
1259         let block_count = 1 + extra_block_count;
1260 
1261         // Blocks need to be sorted in ascending order
1262         self.resources.blocks = (0..block_count)
1263             .map(|i| {
1264                 let is_entry = i == 0;
1265                 let block = builder.create_block();
1266 
1267                 // Optionally mark blocks that are not the entry block as cold
1268                 if !is_entry {
1269                     if bool::arbitrary(self.u)? {
1270                         builder.set_cold_block(block);
1271                     }
1272                 }
1273 
1274                 // The first block has to have the function signature, but for the rest of them we generate
1275                 // a random signature;
1276                 if is_entry {
1277                     builder.append_block_params_for_function_params(block);
1278                     Ok((block, sig.params.iter().map(|a| a.value_type).collect()))
1279                 } else {
1280                     let sig = self.generate_block_signature()?;
1281                     sig.iter().for_each(|ty| {
1282                         builder.append_block_param(block, *ty);
1283                     });
1284                     Ok((block, sig))
1285                 }
1286             })
1287             .collect::<Result<Vec<_>>>()?;
1288 
1289         // Valid blocks for jump tables have to have no parameters in the signature, and must also
1290         // not be the first block.
1291         self.resources.blocks_without_params = self.resources.blocks[1..]
1292             .iter()
1293             .filter(|(_, sig)| sig.len() == 0)
1294             .map(|(b, _)| *b)
1295             .collect();
1296 
1297         Ok(())
1298     }
1299 
1300     fn generate_block_signature(&mut self) -> Result<BlockSignature> {
1301         let param_count = self.param(&self.config.block_signature_params)?;
1302 
1303         let mut params = Vec::with_capacity(param_count);
1304         for _ in 0..param_count {
1305             params.push(self.generate_type()?);
1306         }
1307         Ok(params)
1308     }
1309 
1310     fn build_variable_pool(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1311         let block = builder.current_block().unwrap();
1312 
1313         // Define variables for the function signature
1314         let mut vars: Vec<_> = builder
1315             .func
1316             .signature
1317             .params
1318             .iter()
1319             .map(|param| param.value_type)
1320             .zip(builder.block_params(block).iter().copied())
1321             .collect();
1322 
1323         // Create a pool of vars that are going to be used in this function
1324         for _ in 0..self.param(&self.config.vars_per_function)? {
1325             let ty = self.generate_type()?;
1326             let value = self.generate_const(builder, ty)?;
1327             vars.push((ty, value));
1328         }
1329 
1330         for (id, (ty, value)) in vars.into_iter().enumerate() {
1331             let var = Variable::new(id);
1332             builder.declare_var(var, ty);
1333             builder.def_var(var, value);
1334             self.resources
1335                 .vars
1336                 .entry(ty)
1337                 .or_insert_with(Vec::new)
1338                 .push(var);
1339         }
1340 
1341         Ok(())
1342     }
1343 
1344     /// We generate a function in multiple stages:
1345     ///
1346     /// * First we generate a random number of empty blocks
1347     /// * Then we generate a random pool of variables to be used throughout the function
1348     /// * We then visit each block and generate random instructions
1349     ///
1350     /// Because we generate all blocks and variables up front we already know everything that
1351     /// we need when generating instructions (i.e. jump targets / variables)
1352     pub fn generate(mut self) -> Result<Function> {
1353         let sig = self.generate_signature()?;
1354 
1355         let mut fn_builder_ctx = FunctionBuilderContext::new();
1356         // function name must be in a different namespace than TESTFILE_NAMESPACE (0)
1357         let mut func = Function::with_name_signature(UserFuncName::user(1, 0), sig.clone());
1358 
1359         let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx);
1360 
1361         self.generate_blocks(&mut builder, &sig)?;
1362 
1363         // Function preamble
1364         self.generate_jumptables(&mut builder)?;
1365         self.generate_funcrefs(&mut builder)?;
1366         self.generate_stack_slots(&mut builder)?;
1367 
1368         // Main instruction generation loop
1369         for (block, block_sig) in self.resources.blocks.clone().into_iter() {
1370             let is_block0 = block.as_u32() == 0;
1371             builder.switch_to_block(block);
1372 
1373             if is_block0 {
1374                 // The first block is special because we must create variables both for the
1375                 // block signature and for the variable pool. Additionally, we must also define
1376                 // initial values for all variables that are not the function signature.
1377                 self.build_variable_pool(&mut builder)?;
1378 
1379                 // Stack slots have random bytes at the beginning of the function
1380                 // initialize them to a constant value so that execution stays predictable.
1381                 self.initialize_stack_slots(&mut builder)?;
1382             } else {
1383                 // Define variables for the block params
1384                 for (i, ty) in block_sig.iter().enumerate() {
1385                     let var = self.get_variable_of_type(*ty)?;
1386                     let block_param = builder.block_params(block)[i];
1387                     builder.def_var(var, block_param);
1388                 }
1389             }
1390 
1391             // Generate block instructions
1392             self.generate_instructions(&mut builder)?;
1393 
1394             self.finalize_block(&mut builder, block)?;
1395         }
1396 
1397         builder.seal_all_blocks();
1398         builder.finalize();
1399 
1400         Ok(func)
1401     }
1402 }
1403