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