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