1 use crate::config::Config;
2 use crate::cranelift_arbitrary::CraneliftArbitrary;
3 use anyhow::Result;
4 use arbitrary::{Arbitrary, Unstructured};
5 use cranelift::codegen::data_value::DataValue;
6 use cranelift::codegen::ir::immediates::Offset32;
7 use cranelift::codegen::ir::instructions::{InstructionFormat, ResolvedConstraint};
8 use cranelift::codegen::ir::stackslot::StackSize;
9 
10 use cranelift::codegen::ir::{
11     types::*, AtomicRmwOp, Block, ConstantData, Endianness, ExternalName, FuncRef, Function,
12     LibCall, Opcode, SigRef, Signature, StackSlot, Type, UserExternalName, UserFuncName, Value,
13 };
14 use cranelift::codegen::isa::CallConv;
15 use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Switch, Variable};
16 use cranelift::prelude::isa::OwnedTargetIsa;
17 use cranelift::prelude::{
18     EntityRef, ExtFuncData, FloatCC, InstBuilder, IntCC, JumpTableData, MemFlags, StackSlotData,
19     StackSlotKind,
20 };
21 use once_cell::sync::Lazy;
22 use std::collections::HashMap;
23 use std::ops::RangeInclusive;
24 use target_lexicon::{Architecture, Triple};
25 
26 type BlockSignature = Vec<Type>;
27 
28 fn insert_opcode(
29     fgen: &mut FunctionGenerator,
30     builder: &mut FunctionBuilder,
31     opcode: Opcode,
32     args: &[Type],
33     rets: &[Type],
34 ) -> Result<()> {
35     let mut vals = Vec::with_capacity(args.len());
36     for &arg in args.into_iter() {
37         let var = fgen.get_variable_of_type(arg)?;
38         let val = builder.use_var(var);
39         vals.push(val);
40     }
41 
42     // Some opcodes require us to look at their input arguments to determine the
43     // controlling type. This is not the general case, but we can neatly check this
44     // using `requires_typevar_operand`.
45     let ctrl_type = if opcode.constraints().requires_typevar_operand() {
46         args.first()
47     } else {
48         rets.first()
49     }
50     .copied()
51     .unwrap_or(INVALID);
52 
53     // Choose the appropriate instruction format for this opcode
54     let (inst, dfg) = match opcode.format() {
55         InstructionFormat::NullAry => builder.ins().NullAry(opcode, ctrl_type),
56         InstructionFormat::Unary => builder.ins().Unary(opcode, ctrl_type, vals[0]),
57         InstructionFormat::Binary => builder.ins().Binary(opcode, ctrl_type, vals[0], vals[1]),
58         InstructionFormat::Ternary => builder
59             .ins()
60             .Ternary(opcode, ctrl_type, vals[0], vals[1], vals[2]),
61         _ => unimplemented!(),
62     };
63     let results = dfg.inst_results(inst).to_vec();
64 
65     for (val, &ty) in results.into_iter().zip(rets) {
66         let var = fgen.get_variable_of_type(ty)?;
67         builder.def_var(var, val);
68     }
69     Ok(())
70 }
71 
72 fn insert_call_to_function(
73     fgen: &mut FunctionGenerator,
74     builder: &mut FunctionBuilder,
75     call_opcode: Opcode,
76     sig: &Signature,
77     sig_ref: SigRef,
78     func_ref: FuncRef,
79 ) -> Result<()> {
80     let actuals = fgen.generate_values_for_signature(
81         builder,
82         sig.params.iter().map(|abi_param| abi_param.value_type),
83     )?;
84 
85     let addr_ty = fgen.isa.pointer_type();
86     let call = match call_opcode {
87         Opcode::Call => builder.ins().call(func_ref, &actuals),
88         Opcode::ReturnCall => builder.ins().return_call(func_ref, &actuals),
89         Opcode::CallIndirect => {
90             let addr = builder.ins().func_addr(addr_ty, func_ref);
91             builder.ins().call_indirect(sig_ref, addr, &actuals)
92         }
93         Opcode::ReturnCallIndirect => {
94             let addr = builder.ins().func_addr(addr_ty, func_ref);
95             builder.ins().return_call_indirect(sig_ref, addr, &actuals)
96         }
97         _ => unreachable!(),
98     };
99 
100     // Assign the return values to random variables
101     let ret_values = builder.inst_results(call).to_vec();
102     let ret_types = sig.returns.iter().map(|p| p.value_type);
103     for (ty, val) in ret_types.zip(ret_values) {
104         let var = fgen.get_variable_of_type(ty)?;
105         builder.def_var(var, val);
106     }
107 
108     Ok(())
109 }
110 
111 fn insert_call(
112     fgen: &mut FunctionGenerator,
113     builder: &mut FunctionBuilder,
114     opcode: Opcode,
115     _args: &[Type],
116     _rets: &[Type],
117 ) -> Result<()> {
118     assert!(matches!(opcode, Opcode::Call | Opcode::CallIndirect));
119     let (sig, sig_ref, func_ref) = fgen.u.choose(&fgen.resources.func_refs)?.clone();
120 
121     insert_call_to_function(fgen, builder, opcode, &sig, sig_ref, func_ref)
122 }
123 
124 fn insert_stack_load(
125     fgen: &mut FunctionGenerator,
126     builder: &mut FunctionBuilder,
127     _opcode: Opcode,
128     _args: &[Type],
129     rets: &[Type],
130 ) -> Result<()> {
131     let typevar = rets[0];
132     let type_size = typevar.bytes();
133     let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?;
134     let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32;
135 
136     let val = builder.ins().stack_load(typevar, slot, offset);
137     let var = fgen.get_variable_of_type(typevar)?;
138     builder.def_var(var, val);
139 
140     Ok(())
141 }
142 
143 fn insert_stack_store(
144     fgen: &mut FunctionGenerator,
145     builder: &mut FunctionBuilder,
146     _opcode: Opcode,
147     args: &[Type],
148     _rets: &[Type],
149 ) -> Result<()> {
150     let typevar = args[0];
151     let type_size = typevar.bytes();
152     let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?;
153     let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32;
154 
155     let arg0 = fgen.get_variable_of_type(typevar)?;
156     let arg0 = builder.use_var(arg0);
157 
158     builder.ins().stack_store(arg0, slot, offset);
159     Ok(())
160 }
161 
162 fn insert_cmp(
163     fgen: &mut FunctionGenerator,
164     builder: &mut FunctionBuilder,
165     opcode: Opcode,
166     args: &[Type],
167     rets: &[Type],
168 ) -> Result<()> {
169     let lhs = fgen.get_variable_of_type(args[0])?;
170     let lhs = builder.use_var(lhs);
171 
172     let rhs = fgen.get_variable_of_type(args[1])?;
173     let rhs = builder.use_var(rhs);
174 
175     let res = if opcode == Opcode::Fcmp {
176         let cc = *fgen.u.choose(FloatCC::all())?;
177 
178         // We filter out condition codes that aren't supported by the target at
179         // this point after randomly choosing one, instead of randomly choosing a
180         // supported one, to avoid invalidating the corpus when these get implemented.
181         let unimplemented_cc = match (fgen.isa.triple().architecture, cc) {
182             // Some FloatCC's are not implemented on AArch64, see:
183             // https://github.com/bytecodealliance/wasmtime/issues/4850
184             (Architecture::Aarch64(_), FloatCC::OrderedNotEqual) => true,
185             (Architecture::Aarch64(_), FloatCC::UnorderedOrEqual) => true,
186             (Architecture::Aarch64(_), FloatCC::UnorderedOrLessThan) => true,
187             (Architecture::Aarch64(_), FloatCC::UnorderedOrLessThanOrEqual) => true,
188             (Architecture::Aarch64(_), FloatCC::UnorderedOrGreaterThan) => true,
189             (Architecture::Aarch64(_), FloatCC::UnorderedOrGreaterThanOrEqual) => true,
190 
191             // These are not implemented on x86_64, for vectors.
192             (Architecture::X86_64, FloatCC::UnorderedOrEqual | FloatCC::OrderedNotEqual) => {
193                 args[0].is_vector()
194             }
195             _ => false,
196         };
197         if unimplemented_cc {
198             return Err(arbitrary::Error::IncorrectFormat.into());
199         }
200 
201         builder.ins().fcmp(cc, lhs, rhs)
202     } else {
203         let cc = *fgen.u.choose(IntCC::all())?;
204         builder.ins().icmp(cc, lhs, rhs)
205     };
206 
207     let var = fgen.get_variable_of_type(rets[0])?;
208     builder.def_var(var, res);
209 
210     Ok(())
211 }
212 
213 fn insert_const(
214     fgen: &mut FunctionGenerator,
215     builder: &mut FunctionBuilder,
216     _opcode: Opcode,
217     _args: &[Type],
218     rets: &[Type],
219 ) -> Result<()> {
220     let typevar = rets[0];
221     let var = fgen.get_variable_of_type(typevar)?;
222     let val = fgen.generate_const(builder, typevar)?;
223     builder.def_var(var, val);
224     Ok(())
225 }
226 
227 fn insert_bitcast(
228     fgen: &mut FunctionGenerator,
229     builder: &mut FunctionBuilder,
230     args: &[Type],
231     rets: &[Type],
232 ) -> Result<()> {
233     let from_var = fgen.get_variable_of_type(args[0])?;
234     let from_val = builder.use_var(from_var);
235 
236     let to_var = fgen.get_variable_of_type(rets[0])?;
237 
238     // TODO: We can generate little/big endian flags here.
239     let mut memflags = MemFlags::new();
240 
241     // When bitcasting between vectors of different lane counts, we need to
242     // specify the endianness.
243     if args[0].lane_count() != rets[0].lane_count() {
244         memflags.set_endianness(Endianness::Little);
245     }
246 
247     let res = builder.ins().bitcast(rets[0], memflags, from_val);
248     builder.def_var(to_var, res);
249     Ok(())
250 }
251 
252 fn insert_load_store(
253     fgen: &mut FunctionGenerator,
254     builder: &mut FunctionBuilder,
255     opcode: Opcode,
256     args: &[Type],
257     rets: &[Type],
258 ) -> Result<()> {
259     if opcode == Opcode::Bitcast {
260         return insert_bitcast(fgen, builder, args, rets);
261     }
262 
263     let ctrl_type = *rets.first().or(args.first()).unwrap();
264     let type_size = ctrl_type.bytes();
265 
266     let is_atomic = [Opcode::AtomicLoad, Opcode::AtomicStore].contains(&opcode);
267     let (address, flags, offset) =
268         fgen.generate_address_and_memflags(builder, type_size, is_atomic)?;
269 
270     // The variable being loaded or stored into
271     let var = fgen.get_variable_of_type(ctrl_type)?;
272 
273     match opcode.format() {
274         InstructionFormat::LoadNoOffset => {
275             let (inst, dfg) = builder
276                 .ins()
277                 .LoadNoOffset(opcode, ctrl_type, flags, address);
278 
279             let new_val = dfg.first_result(inst);
280             builder.def_var(var, new_val);
281         }
282         InstructionFormat::StoreNoOffset => {
283             let val = builder.use_var(var);
284 
285             builder
286                 .ins()
287                 .StoreNoOffset(opcode, ctrl_type, flags, val, address);
288         }
289         InstructionFormat::Store => {
290             let val = builder.use_var(var);
291 
292             builder
293                 .ins()
294                 .Store(opcode, ctrl_type, flags, offset, val, address);
295         }
296         InstructionFormat::Load => {
297             let (inst, dfg) = builder
298                 .ins()
299                 .Load(opcode, ctrl_type, flags, offset, address);
300 
301             let new_val = dfg.first_result(inst);
302             builder.def_var(var, new_val);
303         }
304         _ => unimplemented!(),
305     }
306 
307     Ok(())
308 }
309 
310 fn insert_atomic_rmw(
311     fgen: &mut FunctionGenerator,
312     builder: &mut FunctionBuilder,
313     _: Opcode,
314     _: &[Type],
315     rets: &[Type],
316 ) -> Result<()> {
317     let ctrl_type = *rets.first().unwrap();
318     let type_size = ctrl_type.bytes();
319 
320     let rmw_op = *fgen.u.choose(AtomicRmwOp::all())?;
321 
322     let (address, flags, offset) = fgen.generate_address_and_memflags(builder, type_size, true)?;
323 
324     // AtomicRMW does not directly support offsets, so add the offset to the address separately.
325     let address = builder.ins().iadd_imm(address, i64::from(offset));
326 
327     // Load and store target variables
328     let source_var = fgen.get_variable_of_type(ctrl_type)?;
329     let target_var = fgen.get_variable_of_type(ctrl_type)?;
330 
331     let source_val = builder.use_var(source_var);
332     let new_val = builder
333         .ins()
334         .atomic_rmw(ctrl_type, flags, rmw_op, address, source_val);
335 
336     builder.def_var(target_var, new_val);
337     Ok(())
338 }
339 
340 fn insert_atomic_cas(
341     fgen: &mut FunctionGenerator,
342     builder: &mut FunctionBuilder,
343     _: Opcode,
344     _: &[Type],
345     rets: &[Type],
346 ) -> Result<()> {
347     let ctrl_type = *rets.first().unwrap();
348     let type_size = ctrl_type.bytes();
349 
350     let (address, flags, offset) = fgen.generate_address_and_memflags(builder, type_size, true)?;
351 
352     // AtomicCas does not directly support offsets, so add the offset to the address separately.
353     let address = builder.ins().iadd_imm(address, i64::from(offset));
354 
355     // Source and Target variables
356     let expected_var = fgen.get_variable_of_type(ctrl_type)?;
357     let store_var = fgen.get_variable_of_type(ctrl_type)?;
358     let loaded_var = fgen.get_variable_of_type(ctrl_type)?;
359 
360     let expected_val = builder.use_var(expected_var);
361     let store_val = builder.use_var(store_var);
362     let new_val = builder
363         .ins()
364         .atomic_cas(flags, address, expected_val, store_val);
365 
366     builder.def_var(loaded_var, new_val);
367     Ok(())
368 }
369 
370 fn insert_shuffle(
371     fgen: &mut FunctionGenerator,
372     builder: &mut FunctionBuilder,
373     opcode: Opcode,
374     _: &[Type],
375     rets: &[Type],
376 ) -> Result<()> {
377     let ctrl_type = *rets.first().unwrap();
378 
379     let lhs = builder.use_var(fgen.get_variable_of_type(ctrl_type)?);
380     let rhs = builder.use_var(fgen.get_variable_of_type(ctrl_type)?);
381 
382     let mask = {
383         let mut lanes = [0u8; 16];
384         for lane in lanes.iter_mut() {
385             *lane = fgen.u.int_in_range(0..=31)?;
386         }
387         let lanes = ConstantData::from(lanes.as_ref());
388         builder.func.dfg.immediates.push(lanes)
389     };
390 
391     // This function is called for any `InstructionFormat::Shuffle`. Which today is just
392     // `shuffle`, but lets assert that, just to be sure we don't accidentally insert
393     // something else.
394     assert_eq!(opcode, Opcode::Shuffle);
395     let res = builder.ins().shuffle(lhs, rhs, mask);
396 
397     let target_var = fgen.get_variable_of_type(ctrl_type)?;
398     builder.def_var(target_var, res);
399 
400     Ok(())
401 }
402 
403 fn insert_ins_ext_lane(
404     fgen: &mut FunctionGenerator,
405     builder: &mut FunctionBuilder,
406     opcode: Opcode,
407     args: &[Type],
408     rets: &[Type],
409 ) -> Result<()> {
410     let vector_type = *args.first().unwrap();
411     let ret_type = *rets.first().unwrap();
412 
413     let lhs = builder.use_var(fgen.get_variable_of_type(vector_type)?);
414     let max_lane = (vector_type.lane_count() as u8) - 1;
415     let lane = fgen.u.int_in_range(0..=max_lane)?;
416 
417     let res = match opcode {
418         Opcode::Insertlane => {
419             let rhs = builder.use_var(fgen.get_variable_of_type(args[1])?);
420             builder.ins().insertlane(lhs, rhs, lane)
421         }
422         Opcode::Extractlane => builder.ins().extractlane(lhs, lane),
423         _ => todo!(),
424     };
425 
426     let target_var = fgen.get_variable_of_type(ret_type)?;
427     builder.def_var(target_var, res);
428 
429     Ok(())
430 }
431 
432 type OpcodeInserter = fn(
433     fgen: &mut FunctionGenerator,
434     builder: &mut FunctionBuilder,
435     Opcode,
436     &[Type],
437     &[Type],
438 ) -> Result<()>;
439 
440 macro_rules! exceptions {
441     ($op:expr, $args:expr, $rets:expr, $(($($cases:pat),*)),* $(,)?) => {
442         match ($op, $args, $rets) {
443             $( ($($cases,)* ..) => return false, )*
444             _ => true,
445         }
446     }
447 }
448 
449 /// Returns true if we believe this `OpcodeSignature` should compile correctly
450 /// for the given target triple. We currently have a range of known issues
451 /// with specific lowerings on specific backends, and we don't want to get
452 /// fuzz bug reports for those. Over time our goal is to eliminate all of these
453 /// exceptions.
454 fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -> bool {
455     // Rule out invalid combinations that we don't yet have a good way of rejecting with the
456     // instruction DSL type constraints.
457     match op {
458         Opcode::FcvtToUintSat | Opcode::FcvtToSintSat => {
459             assert_eq!(args.len(), 1);
460             assert_eq!(rets.len(), 1);
461 
462             let arg = args[0];
463             let ret = rets[0];
464 
465             // Vector arguments must produce vector results, and scalar arguments must produce
466             // scalar results.
467             if arg.is_vector() != ret.is_vector() {
468                 return false;
469             }
470 
471             if arg.is_vector() && ret.is_vector() {
472                 // Vector conversions must have the same number of lanes, and the lanes must be the
473                 // same bit-width.
474                 if arg.lane_count() != ret.lane_count() {
475                     return false;
476                 }
477 
478                 if arg.lane_of().bits() != ret.lane_of().bits() {
479                     return false;
480                 }
481             }
482         }
483 
484         Opcode::Bitcast => {
485             assert_eq!(args.len(), 1);
486             assert_eq!(rets.len(), 1);
487 
488             let arg = args[0];
489             let ret = rets[0];
490 
491             // The opcode generator still allows bitcasts between different sized types, but these
492             // are rejected in the verifier.
493             if arg.bits() != ret.bits() {
494                 return false;
495             }
496         }
497 
498         _ => {}
499     }
500 
501     match triple.architecture {
502         Architecture::X86_64 => {
503             exceptions!(
504                 op,
505                 args,
506                 rets,
507                 (Opcode::UmulOverflow | Opcode::SmulOverflow, &[I128, I128]),
508                 (Opcode::Imul, &[I8X16, I8X16]),
509                 // https://github.com/bytecodealliance/wasmtime/issues/5468
510                 (Opcode::Smulhi | Opcode::Umulhi, &[I8, I8]),
511                 // https://github.com/bytecodealliance/wasmtime/issues/4756
512                 (Opcode::Udiv | Opcode::Sdiv, &[I128, I128]),
513                 // https://github.com/bytecodealliance/wasmtime/issues/5474
514                 (Opcode::Urem | Opcode::Srem, &[I128, I128]),
515                 // https://github.com/bytecodealliance/wasmtime/issues/5466
516                 (Opcode::Iabs, &[I128]),
517                 // https://github.com/bytecodealliance/wasmtime/issues/3370
518                 (
519                     Opcode::Smin | Opcode::Umin | Opcode::Smax | Opcode::Umax,
520                     &[I128, I128]
521                 ),
522                 // https://github.com/bytecodealliance/wasmtime/issues/5107
523                 (Opcode::Cls, &[I8], &[I8]),
524                 (Opcode::Cls, &[I16], &[I16]),
525                 (Opcode::Cls, &[I32], &[I32]),
526                 (Opcode::Cls, &[I64], &[I64]),
527                 (Opcode::Cls, &[I128], &[I128]),
528                 // https://github.com/bytecodealliance/wasmtime/issues/4897
529                 // https://github.com/bytecodealliance/wasmtime/issues/4899
530                 (
531                     Opcode::FcvtToUint
532                         | Opcode::FcvtToUintSat
533                         | Opcode::FcvtToSint
534                         | Opcode::FcvtToSintSat,
535                     &[F32 | F64],
536                     &[I8 | I16 | I128]
537                 ),
538                 (Opcode::FcvtToUint | Opcode::FcvtToSint, &[F32X4], &[I32X4]),
539                 (
540                     Opcode::FcvtToUint
541                         | Opcode::FcvtToUintSat
542                         | Opcode::FcvtToSint
543                         | Opcode::FcvtToSintSat,
544                     &[F64X2],
545                     &[I64X2]
546                 ),
547                 // https://github.com/bytecodealliance/wasmtime/issues/4900
548                 (Opcode::FcvtFromUint, &[I128], &[F32 | F64]),
549                 // This has a lowering, but only when preceded by `uwiden_low`.
550                 (Opcode::FcvtFromUint, &[I64X2], &[F64X2]),
551                 // https://github.com/bytecodealliance/wasmtime/issues/4900
552                 (Opcode::FcvtFromSint, &[I128], &[F32 | F64]),
553                 (Opcode::FcvtFromSint, &[I64X2], &[F64X2]),
554                 (
555                     Opcode::Umulhi | Opcode::Smulhi,
556                     &([I8X16, I8X16] | [I16X8, I16X8] | [I32X4, I32X4] | [I64X2, I64X2])
557                 ),
558                 (
559                     Opcode::UaddSat | Opcode::SaddSat | Opcode::UsubSat | Opcode::SsubSat,
560                     &([I32X4, I32X4] | [I64X2, I64X2])
561                 ),
562                 (Opcode::Fcopysign, &([F32X4, F32X4] | [F64X2, F64X2])),
563                 (Opcode::Popcnt, &([I8X16] | [I16X8] | [I32X4] | [I64X2])),
564                 (
565                     Opcode::Umax | Opcode::Smax | Opcode::Umin | Opcode::Smin,
566                     &[I64X2, I64X2]
567                 ),
568                 // https://github.com/bytecodealliance/wasmtime/issues/6104
569                 (Opcode::Bitcast, &[I128], &[_]),
570                 (Opcode::Bitcast, &[_], &[I128]),
571                 (Opcode::Uunarrow),
572                 (Opcode::Snarrow | Opcode::Unarrow, &[I64X2, I64X2]),
573                 (Opcode::SqmulRoundSat, &[I32X4, I32X4]),
574                 // This Icmp is not implemented: #5529
575                 (Opcode::Icmp, &[I64X2, I64X2]),
576                 // IaddPairwise is implemented, but only for some types, and with some preceding ops.
577                 (Opcode::IaddPairwise),
578                 // Nothing wrong with this select. But we have an isle rule that can optimize it
579                 // into a `min`/`max` instructions, which we don't have implemented yet.
580                 (Opcode::Select, &[_, I128, I128]),
581                 // These stack accesses can cause segfaults if they are merged into an SSE instruction.
582                 // See: #5922
583                 (
584                     Opcode::StackStore,
585                     &[I8X16 | I16X8 | I32X4 | I64X2 | F32X4 | F64X2]
586                 ),
587                 (
588                     Opcode::StackLoad,
589                     &[],
590                     &[I8X16 | I16X8 | I32X4 | I64X2 | F32X4 | F64X2]
591                 ),
592             )
593         }
594 
595         Architecture::Aarch64(_) => {
596             exceptions!(
597                 op,
598                 args,
599                 rets,
600                 (Opcode::UmulOverflow | Opcode::SmulOverflow, &[I128, I128]),
601                 // https://github.com/bytecodealliance/wasmtime/issues/4864
602                 (Opcode::Udiv | Opcode::Sdiv, &[I128, I128]),
603                 // https://github.com/bytecodealliance/wasmtime/issues/5472
604                 (Opcode::Urem | Opcode::Srem, &[I128, I128]),
605                 // https://github.com/bytecodealliance/wasmtime/issues/5467
606                 (Opcode::Iabs, &[I128]),
607                 // https://github.com/bytecodealliance/wasmtime/issues/4313
608                 (
609                     Opcode::Smin | Opcode::Umin | Opcode::Smax | Opcode::Umax,
610                     &[I128, I128]
611                 ),
612                 // https://github.com/bytecodealliance/wasmtime/issues/4870
613                 (Opcode::Bnot, &[F32 | F64]),
614                 (
615                     Opcode::Band
616                         | Opcode::Bor
617                         | Opcode::Bxor
618                         | Opcode::BandNot
619                         | Opcode::BorNot
620                         | Opcode::BxorNot,
621                     &([F32, F32] | [F64, F64])
622                 ),
623                 // https://github.com/bytecodealliance/wasmtime/issues/5198
624                 (Opcode::Bitselect, &[I128, I128, I128]),
625                 // https://github.com/bytecodealliance/wasmtime/issues/4934
626                 (
627                     Opcode::FcvtToUint
628                         | Opcode::FcvtToUintSat
629                         | Opcode::FcvtToSint
630                         | Opcode::FcvtToSintSat,
631                     &[F32 | F64]
632                 ),
633                 // https://github.com/bytecodealliance/wasmtime/issues/4933
634                 (
635                     Opcode::FcvtFromUint | Opcode::FcvtFromSint,
636                     &[I128],
637                     &[F32 | F64]
638                 ),
639                 (
640                     Opcode::Umulhi | Opcode::Smulhi,
641                     &([I8X16, I8X16] | [I16X8, I16X8] | [I32X4, I32X4] | [I64X2, I64X2])
642                 ),
643                 (Opcode::Popcnt, &[I16X8 | I32X4 | I64X2]),
644                 // Nothing wrong with this select. But we have an isle rule that can optimize it
645                 // into a `min`/`max` instructions, which we don't have implemented yet.
646                 (Opcode::Select, &[I8, I128, I128]),
647                 // https://github.com/bytecodealliance/wasmtime/issues/6104
648                 (Opcode::Bitcast, &[I128], &[_]),
649                 (Opcode::Bitcast, &[_], &[I128]),
650             )
651         }
652 
653         Architecture::S390x => {
654             exceptions!(
655                 op,
656                 args,
657                 rets,
658                 (Opcode::UaddOverflow | Opcode::SaddOverflow),
659                 (Opcode::UsubOverflow | Opcode::SsubOverflow),
660                 (Opcode::UmulOverflow | Opcode::SmulOverflow),
661                 (
662                     Opcode::Udiv | Opcode::Sdiv | Opcode::Urem | Opcode::Srem,
663                     &[I128, I128]
664                 ),
665                 (Opcode::Bnot, &[F32 | F64]),
666                 (
667                     Opcode::Band
668                         | Opcode::Bor
669                         | Opcode::Bxor
670                         | Opcode::BandNot
671                         | Opcode::BorNot
672                         | Opcode::BxorNot,
673                     &([F32, F32] | [F64, F64])
674                 ),
675                 (
676                     Opcode::FcvtToUint
677                         | Opcode::FcvtToUintSat
678                         | Opcode::FcvtToSint
679                         | Opcode::FcvtToSintSat,
680                     &[F32 | F64],
681                     &[I128]
682                 ),
683                 (
684                     Opcode::FcvtFromUint | Opcode::FcvtFromSint,
685                     &[I128],
686                     &[F32 | F64]
687                 ),
688                 (Opcode::SsubSat | Opcode::SaddSat, &[I64X2, I64X2]),
689                 // https://github.com/bytecodealliance/wasmtime/issues/6104
690                 (Opcode::Bitcast, &[I128], &[_]),
691                 (Opcode::Bitcast, &[_], &[I128]),
692             )
693         }
694 
695         Architecture::Riscv64(_) => {
696             // RISC-V Does not support SIMD at all
697             let is_simd = args.iter().chain(rets).any(|t| t.is_vector());
698             if is_simd {
699                 return false;
700             }
701 
702             exceptions!(
703                 op,
704                 args,
705                 rets,
706                 // TODO
707                 (Opcode::UaddOverflow | Opcode::SaddOverflow),
708                 (Opcode::UsubOverflow | Opcode::SsubOverflow),
709                 (Opcode::UmulOverflow | Opcode::SmulOverflow),
710                 // TODO
711                 (
712                     Opcode::Udiv | Opcode::Sdiv | Opcode::Urem | Opcode::Srem,
713                     &[I128, I128]
714                 ),
715                 // TODO
716                 (Opcode::Iabs, &[I128]),
717                 // TODO
718                 (Opcode::Bitselect, &[I128, I128, I128]),
719                 // https://github.com/bytecodealliance/wasmtime/issues/5528
720                 (
721                     Opcode::FcvtToUint | Opcode::FcvtToSint,
722                     [F32 | F64],
723                     &[I128]
724                 ),
725                 (
726                     Opcode::FcvtToUintSat | Opcode::FcvtToSintSat,
727                     &[F32 | F64],
728                     &[I8 | I16 | I128]
729                 ),
730                 // https://github.com/bytecodealliance/wasmtime/issues/5528
731                 (
732                     Opcode::FcvtFromUint | Opcode::FcvtFromSint,
733                     &[I128],
734                     &[F32 | F64]
735                 ),
736                 // https://github.com/bytecodealliance/wasmtime/issues/6104
737                 (Opcode::Bitcast, &[I128], &[_]),
738                 (Opcode::Bitcast, &[_], &[I128]),
739                 // TODO
740                 (Opcode::SelectSpectreGuard, &[_, _, _], &[F32]),
741                 (Opcode::SelectSpectreGuard, &[_, _, _], &[F64]),
742             )
743         }
744 
745         _ => true,
746     }
747 }
748 
749 type OpcodeSignature = (Opcode, Vec<Type>, Vec<Type>);
750 
751 static OPCODE_SIGNATURES: Lazy<Vec<OpcodeSignature>> = Lazy::new(|| {
752     let types = &[
753         I8, I16, I32, I64, I128, // Scalar Integers
754         F32, F64, // Scalar Floats
755         I8X16, I16X8, I32X4, I64X2, // SIMD Integers
756         F32X4, F64X2, // SIMD Floats
757     ];
758 
759     Opcode::all()
760         .iter()
761         .filter(|op| {
762             match op {
763                 // Control flow opcodes should not be generated through `generate_instructions`.
764                 Opcode::BrTable
765                 | Opcode::Brif
766                 | Opcode::Jump
767                 | Opcode::Return
768                 | Opcode::ReturnCall
769                 | Opcode::ReturnCallIndirect => false,
770 
771                 // Constants are generated outside of `generate_instructions`
772                 Opcode::Iconst => false,
773 
774                 // TODO: extract_vector raises exceptions during return type generation becuase it
775                 // uses dynamic vectors.
776                 Opcode::ExtractVector => false,
777 
778                 _ => true,
779             }
780         })
781         .flat_map(|op| {
782             let constraints = op.constraints();
783 
784             let ctrl_types = if let Some(ctrls) = constraints.ctrl_typeset() {
785                 Vec::from_iter(types.iter().copied().filter(|ty| ctrls.contains(*ty)))
786             } else {
787                 vec![INVALID]
788             };
789 
790             ctrl_types.into_iter().flat_map(move |ctrl_type| {
791                 let rets = Vec::from_iter(
792                     (0..constraints.num_fixed_results())
793                         .map(|i| constraints.result_type(i, ctrl_type)),
794                 );
795 
796                 // Cols is a vector whose length will match `num_fixed_value_arguments`, and whose
797                 // elements will be vectors of types that are valid for that fixed argument
798                 // position.
799                 let mut cols = vec![];
800 
801                 for i in 0..constraints.num_fixed_value_arguments() {
802                     match constraints.value_argument_constraint(i, ctrl_type) {
803                         ResolvedConstraint::Bound(ty) => cols.push(Vec::from([ty])),
804                         ResolvedConstraint::Free(tys) => cols.push(Vec::from_iter(
805                             types.iter().copied().filter(|ty| tys.contains(*ty)),
806                         )),
807                     }
808                 }
809 
810                 // Generate the cartesian product of cols to produce a vector of argument lists,
811                 // argss. The argss vector is seeded with the empty argument list, so there's an
812                 // initial value to be extended in the loop below.
813                 let mut argss = vec![vec![]];
814                 let mut cols = cols.as_slice();
815                 while let Some((col, rest)) = cols.split_last() {
816                     cols = rest;
817 
818                     let mut next = vec![];
819                     for current in argss.iter() {
820                         // Extend the front of each argument candidate with every type in `col`.
821                         for ty in col {
822                             let mut args = vec![*ty];
823                             args.extend_from_slice(&current);
824                             next.push(args);
825                         }
826                     }
827 
828                     let _ = std::mem::replace(&mut argss, next);
829                 }
830 
831                 argss.into_iter().map(move |args| (*op, args, rets.clone()))
832             })
833         })
834         .filter(|(op, args, rets)| {
835             // These op/signature combinations need to be vetted
836             exceptions!(
837                 op,
838                 args.as_slice(),
839                 rets.as_slice(),
840                 (Opcode::Debugtrap),
841                 (Opcode::Trap),
842                 (Opcode::Trapz),
843                 (Opcode::ResumableTrap),
844                 (Opcode::Trapnz),
845                 (Opcode::ResumableTrapnz),
846                 (Opcode::CallIndirect, &[I32]),
847                 (Opcode::FuncAddr),
848                 (Opcode::X86Pshufb),
849                 (Opcode::AvgRound),
850                 (Opcode::Uload8x8),
851                 (Opcode::Sload8x8),
852                 (Opcode::Uload16x4),
853                 (Opcode::Sload16x4),
854                 (Opcode::Uload32x2),
855                 (Opcode::Sload32x2),
856                 (Opcode::StackAddr),
857                 (Opcode::DynamicStackLoad),
858                 (Opcode::DynamicStackStore),
859                 (Opcode::DynamicStackAddr),
860                 (Opcode::GlobalValue),
861                 (Opcode::SymbolValue),
862                 (Opcode::TlsValue),
863                 (Opcode::GetPinnedReg),
864                 (Opcode::SetPinnedReg),
865                 (Opcode::GetFramePointer),
866                 (Opcode::GetStackPointer),
867                 (Opcode::GetReturnAddress),
868                 (Opcode::TableAddr),
869                 (Opcode::Null),
870                 (Opcode::X86Blendv),
871                 (Opcode::VallTrue),
872                 (Opcode::IcmpImm),
873                 (Opcode::X86Pmulhrsw),
874                 (Opcode::IaddImm),
875                 (Opcode::ImulImm),
876                 (Opcode::UdivImm),
877                 (Opcode::SdivImm),
878                 (Opcode::UremImm),
879                 (Opcode::SremImm),
880                 (Opcode::IrsubImm),
881                 (Opcode::IaddCin),
882                 (Opcode::IaddCarry),
883                 (Opcode::UaddOverflowTrap),
884                 (Opcode::IsubBin),
885                 (Opcode::IsubBorrow),
886                 (Opcode::BandImm),
887                 (Opcode::BorImm),
888                 (Opcode::BxorImm),
889                 (Opcode::RotlImm),
890                 (Opcode::RotrImm),
891                 (Opcode::IshlImm),
892                 (Opcode::UshrImm),
893                 (Opcode::SshrImm),
894                 (Opcode::IsNull),
895                 (Opcode::IsInvalid),
896                 (Opcode::ScalarToVector),
897                 (Opcode::X86Pmaddubsw),
898                 (Opcode::X86Cvtt2dq),
899                 (Opcode::Bitselect, &[F32, F32, F32], &[F32]),
900                 (Opcode::Bitselect, &[F64, F64, F64], &[F64]),
901                 (Opcode::Bitselect, &[F32X4, F32X4, F32X4], &[F32X4]),
902                 (Opcode::Bitselect, &[F64X2, F64X2, F64X2], &[F64X2]),
903                 (Opcode::VanyTrue, &[F32X4], &[I8]),
904                 (Opcode::VanyTrue, &[F64X2], &[I8]),
905                 (Opcode::VhighBits, &[F32X4], &[I8]),
906                 (Opcode::VhighBits, &[F64X2], &[I8]),
907                 (Opcode::VhighBits, &[I8X16], &[I16]),
908                 (Opcode::VhighBits, &[I16X8], &[I16]),
909                 (Opcode::VhighBits, &[I32X4], &[I16]),
910                 (Opcode::VhighBits, &[I64X2], &[I16]),
911                 (Opcode::VhighBits, &[F32X4], &[I16]),
912                 (Opcode::VhighBits, &[F64X2], &[I16]),
913                 (Opcode::VhighBits, &[I8X16], &[I32]),
914                 (Opcode::VhighBits, &[I16X8], &[I32]),
915                 (Opcode::VhighBits, &[I32X4], &[I32]),
916                 (Opcode::VhighBits, &[I64X2], &[I32]),
917                 (Opcode::VhighBits, &[F32X4], &[I32]),
918                 (Opcode::VhighBits, &[F64X2], &[I32]),
919                 (Opcode::VhighBits, &[I8X16], &[I64]),
920                 (Opcode::VhighBits, &[I16X8], &[I64]),
921                 (Opcode::VhighBits, &[I32X4], &[I64]),
922                 (Opcode::VhighBits, &[I64X2], &[I64]),
923                 (Opcode::VhighBits, &[F32X4], &[I64]),
924                 (Opcode::VhighBits, &[F64X2], &[I64]),
925                 (Opcode::VhighBits, &[I8X16], &[I128]),
926                 (Opcode::VhighBits, &[I16X8], &[I128]),
927                 (Opcode::VhighBits, &[I32X4], &[I128]),
928                 (Opcode::VhighBits, &[I64X2], &[I128]),
929                 (Opcode::VhighBits, &[F32X4], &[I128]),
930                 (Opcode::VhighBits, &[F64X2], &[I128]),
931                 (Opcode::VhighBits, &[I8X16], &[I8X16]),
932                 (Opcode::VhighBits, &[I16X8], &[I8X16]),
933                 (Opcode::VhighBits, &[I32X4], &[I8X16]),
934                 (Opcode::VhighBits, &[I64X2], &[I8X16]),
935                 (Opcode::VhighBits, &[F32X4], &[I8X16]),
936                 (Opcode::VhighBits, &[F64X2], &[I8X16]),
937                 (Opcode::VhighBits, &[I8X16], &[I16X8]),
938                 (Opcode::VhighBits, &[I16X8], &[I16X8]),
939                 (Opcode::VhighBits, &[I32X4], &[I16X8]),
940                 (Opcode::VhighBits, &[I64X2], &[I16X8]),
941                 (Opcode::VhighBits, &[F32X4], &[I16X8]),
942                 (Opcode::VhighBits, &[F64X2], &[I16X8]),
943                 (Opcode::VhighBits, &[I8X16], &[I32X4]),
944                 (Opcode::VhighBits, &[I16X8], &[I32X4]),
945                 (Opcode::VhighBits, &[I32X4], &[I32X4]),
946                 (Opcode::VhighBits, &[I64X2], &[I32X4]),
947                 (Opcode::VhighBits, &[F32X4], &[I32X4]),
948                 (Opcode::VhighBits, &[F64X2], &[I32X4]),
949                 (Opcode::VhighBits, &[I8X16], &[I64X2]),
950                 (Opcode::VhighBits, &[I16X8], &[I64X2]),
951                 (Opcode::VhighBits, &[I32X4], &[I64X2]),
952                 (Opcode::VhighBits, &[I64X2], &[I64X2]),
953                 (Opcode::VhighBits, &[F32X4], &[I64X2]),
954                 (Opcode::VhighBits, &[F64X2], &[I64X2]),
955                 (Opcode::Ineg, &[I8X16], &[I8X16]),
956                 (Opcode::Ineg, &[I16X8], &[I16X8]),
957                 (Opcode::Ineg, &[I32X4], &[I32X4]),
958                 (Opcode::Ineg, &[I64X2], &[I64X2]),
959                 (Opcode::Umulhi, &[I128, I128], &[I128]),
960                 (Opcode::Smulhi, &[I128, I128], &[I128]),
961                 // https://github.com/bytecodealliance/wasmtime/issues/6073
962                 (Opcode::Iconcat, &[I32, I32], &[I64]),
963                 (Opcode::Iconcat, &[I16, I16], &[I32]),
964                 (Opcode::Iconcat, &[I8, I8], &[I16]),
965                 // https://github.com/bytecodealliance/wasmtime/issues/6073
966                 (Opcode::Isplit, &[I64], &[I32, I32]),
967                 (Opcode::Isplit, &[I32], &[I16, I16]),
968                 (Opcode::Isplit, &[I16], &[I8, I8]),
969                 (Opcode::Rotl, &[I8X16, I8], &[I8X16]),
970                 (Opcode::Rotl, &[I8X16, I16], &[I8X16]),
971                 (Opcode::Rotl, &[I8X16, I32], &[I8X16]),
972                 (Opcode::Rotl, &[I8X16, I64], &[I8X16]),
973                 (Opcode::Rotl, &[I8X16, I128], &[I8X16]),
974                 (Opcode::Rotl, &[I16X8, I8], &[I16X8]),
975                 (Opcode::Rotl, &[I16X8, I16], &[I16X8]),
976                 (Opcode::Rotl, &[I16X8, I32], &[I16X8]),
977                 (Opcode::Rotl, &[I16X8, I64], &[I16X8]),
978                 (Opcode::Rotl, &[I16X8, I128], &[I16X8]),
979                 (Opcode::Rotl, &[I32X4, I8], &[I32X4]),
980                 (Opcode::Rotl, &[I32X4, I16], &[I32X4]),
981                 (Opcode::Rotl, &[I32X4, I32], &[I32X4]),
982                 (Opcode::Rotl, &[I32X4, I64], &[I32X4]),
983                 (Opcode::Rotl, &[I32X4, I128], &[I32X4]),
984                 (Opcode::Rotl, &[I64X2, I8], &[I64X2]),
985                 (Opcode::Rotl, &[I64X2, I16], &[I64X2]),
986                 (Opcode::Rotl, &[I64X2, I32], &[I64X2]),
987                 (Opcode::Rotl, &[I64X2, I64], &[I64X2]),
988                 (Opcode::Rotl, &[I64X2, I128], &[I64X2]),
989                 (Opcode::Rotr, &[I8X16, I8], &[I8X16]),
990                 (Opcode::Rotr, &[I8X16, I16], &[I8X16]),
991                 (Opcode::Rotr, &[I8X16, I32], &[I8X16]),
992                 (Opcode::Rotr, &[I8X16, I64], &[I8X16]),
993                 (Opcode::Rotr, &[I8X16, I128], &[I8X16]),
994                 (Opcode::Rotr, &[I16X8, I8], &[I16X8]),
995                 (Opcode::Rotr, &[I16X8, I16], &[I16X8]),
996                 (Opcode::Rotr, &[I16X8, I32], &[I16X8]),
997                 (Opcode::Rotr, &[I16X8, I64], &[I16X8]),
998                 (Opcode::Rotr, &[I16X8, I128], &[I16X8]),
999                 (Opcode::Rotr, &[I32X4, I8], &[I32X4]),
1000                 (Opcode::Rotr, &[I32X4, I16], &[I32X4]),
1001                 (Opcode::Rotr, &[I32X4, I32], &[I32X4]),
1002                 (Opcode::Rotr, &[I32X4, I64], &[I32X4]),
1003                 (Opcode::Rotr, &[I32X4, I128], &[I32X4]),
1004                 (Opcode::Rotr, &[I64X2, I8], &[I64X2]),
1005                 (Opcode::Rotr, &[I64X2, I16], &[I64X2]),
1006                 (Opcode::Rotr, &[I64X2, I32], &[I64X2]),
1007                 (Opcode::Rotr, &[I64X2, I64], &[I64X2]),
1008                 (Opcode::Rotr, &[I64X2, I128], &[I64X2]),
1009                 (Opcode::Ishl, &[I8X16, I8], &[I8X16]),
1010                 (Opcode::Ishl, &[I8X16, I16], &[I8X16]),
1011                 (Opcode::Ishl, &[I8X16, I32], &[I8X16]),
1012                 (Opcode::Ishl, &[I8X16, I64], &[I8X16]),
1013                 (Opcode::Ishl, &[I8X16, I128], &[I8X16]),
1014                 (Opcode::Ishl, &[I16X8, I8], &[I16X8]),
1015                 (Opcode::Ishl, &[I16X8, I16], &[I16X8]),
1016                 (Opcode::Ishl, &[I16X8, I32], &[I16X8]),
1017                 (Opcode::Ishl, &[I16X8, I64], &[I16X8]),
1018                 (Opcode::Ishl, &[I16X8, I128], &[I16X8]),
1019                 (Opcode::Ishl, &[I32X4, I8], &[I32X4]),
1020                 (Opcode::Ishl, &[I32X4, I16], &[I32X4]),
1021                 (Opcode::Ishl, &[I32X4, I32], &[I32X4]),
1022                 (Opcode::Ishl, &[I32X4, I64], &[I32X4]),
1023                 (Opcode::Ishl, &[I32X4, I128], &[I32X4]),
1024                 (Opcode::Ishl, &[I64X2, I8], &[I64X2]),
1025                 (Opcode::Ishl, &[I64X2, I16], &[I64X2]),
1026                 (Opcode::Ishl, &[I64X2, I32], &[I64X2]),
1027                 (Opcode::Ishl, &[I64X2, I64], &[I64X2]),
1028                 (Opcode::Ishl, &[I64X2, I128], &[I64X2]),
1029                 (Opcode::Ushr, &[I8X16, I8], &[I8X16]),
1030                 (Opcode::Ushr, &[I8X16, I16], &[I8X16]),
1031                 (Opcode::Ushr, &[I8X16, I32], &[I8X16]),
1032                 (Opcode::Ushr, &[I8X16, I64], &[I8X16]),
1033                 (Opcode::Ushr, &[I8X16, I128], &[I8X16]),
1034                 (Opcode::Ushr, &[I16X8, I8], &[I16X8]),
1035                 (Opcode::Ushr, &[I16X8, I16], &[I16X8]),
1036                 (Opcode::Ushr, &[I16X8, I32], &[I16X8]),
1037                 (Opcode::Ushr, &[I16X8, I64], &[I16X8]),
1038                 (Opcode::Ushr, &[I16X8, I128], &[I16X8]),
1039                 (Opcode::Ushr, &[I32X4, I8], &[I32X4]),
1040                 (Opcode::Ushr, &[I32X4, I16], &[I32X4]),
1041                 (Opcode::Ushr, &[I32X4, I32], &[I32X4]),
1042                 (Opcode::Ushr, &[I32X4, I64], &[I32X4]),
1043                 (Opcode::Ushr, &[I32X4, I128], &[I32X4]),
1044                 (Opcode::Ushr, &[I64X2, I8], &[I64X2]),
1045                 (Opcode::Ushr, &[I64X2, I16], &[I64X2]),
1046                 (Opcode::Ushr, &[I64X2, I32], &[I64X2]),
1047                 (Opcode::Ushr, &[I64X2, I64], &[I64X2]),
1048                 (Opcode::Ushr, &[I64X2, I128], &[I64X2]),
1049                 (Opcode::Sshr, &[I8X16, I8], &[I8X16]),
1050                 (Opcode::Sshr, &[I8X16, I16], &[I8X16]),
1051                 (Opcode::Sshr, &[I8X16, I32], &[I8X16]),
1052                 (Opcode::Sshr, &[I8X16, I64], &[I8X16]),
1053                 (Opcode::Sshr, &[I8X16, I128], &[I8X16]),
1054                 (Opcode::Sshr, &[I16X8, I8], &[I16X8]),
1055                 (Opcode::Sshr, &[I16X8, I16], &[I16X8]),
1056                 (Opcode::Sshr, &[I16X8, I32], &[I16X8]),
1057                 (Opcode::Sshr, &[I16X8, I64], &[I16X8]),
1058                 (Opcode::Sshr, &[I16X8, I128], &[I16X8]),
1059                 (Opcode::Sshr, &[I32X4, I8], &[I32X4]),
1060                 (Opcode::Sshr, &[I32X4, I16], &[I32X4]),
1061                 (Opcode::Sshr, &[I32X4, I32], &[I32X4]),
1062                 (Opcode::Sshr, &[I32X4, I64], &[I32X4]),
1063                 (Opcode::Sshr, &[I32X4, I128], &[I32X4]),
1064                 (Opcode::Sshr, &[I64X2, I8], &[I64X2]),
1065                 (Opcode::Sshr, &[I64X2, I16], &[I64X2]),
1066                 (Opcode::Sshr, &[I64X2, I32], &[I64X2]),
1067                 (Opcode::Sshr, &[I64X2, I64], &[I64X2]),
1068                 (Opcode::Sshr, &[I64X2, I128], &[I64X2]),
1069                 (Opcode::Fmin, &[F32X4, F32X4], &[F32X4]),
1070                 (Opcode::Fmin, &[F64X2, F64X2], &[F64X2]),
1071                 (Opcode::Fmax, &[F32X4, F32X4], &[F32X4]),
1072                 (Opcode::Fmax, &[F64X2, F64X2], &[F64X2]),
1073                 (Opcode::FcvtToUintSat, &[F32X4], &[I8]),
1074                 (Opcode::FcvtToUintSat, &[F64X2], &[I8]),
1075                 (Opcode::FcvtToUintSat, &[F32X4], &[I16]),
1076                 (Opcode::FcvtToUintSat, &[F64X2], &[I16]),
1077                 (Opcode::FcvtToUintSat, &[F32X4], &[I32]),
1078                 (Opcode::FcvtToUintSat, &[F64X2], &[I32]),
1079                 (Opcode::FcvtToUintSat, &[F32X4], &[I64]),
1080                 (Opcode::FcvtToUintSat, &[F64X2], &[I64]),
1081                 (Opcode::FcvtToUintSat, &[F32X4], &[I128]),
1082                 (Opcode::FcvtToUintSat, &[F64X2], &[I128]),
1083                 (Opcode::FcvtToUintSat, &[F32], &[I8X16]),
1084                 (Opcode::FcvtToUintSat, &[F64], &[I8X16]),
1085                 (Opcode::FcvtToUintSat, &[F32X4], &[I8X16]),
1086                 (Opcode::FcvtToUintSat, &[F64X2], &[I8X16]),
1087                 (Opcode::FcvtToUintSat, &[F32], &[I16X8]),
1088                 (Opcode::FcvtToUintSat, &[F64], &[I16X8]),
1089                 (Opcode::FcvtToUintSat, &[F32X4], &[I16X8]),
1090                 (Opcode::FcvtToUintSat, &[F64X2], &[I16X8]),
1091                 (Opcode::FcvtToUintSat, &[F32], &[I32X4]),
1092                 (Opcode::FcvtToUintSat, &[F64], &[I32X4]),
1093                 (Opcode::FcvtToUintSat, &[F64X2], &[I32X4]),
1094                 (Opcode::FcvtToUintSat, &[F32], &[I64X2]),
1095                 (Opcode::FcvtToUintSat, &[F64], &[I64X2]),
1096                 (Opcode::FcvtToUintSat, &[F32X4], &[I64X2]),
1097                 (Opcode::FcvtToSintSat, &[F32X4], &[I8]),
1098                 (Opcode::FcvtToSintSat, &[F64X2], &[I8]),
1099                 (Opcode::FcvtToSintSat, &[F32X4], &[I16]),
1100                 (Opcode::FcvtToSintSat, &[F64X2], &[I16]),
1101                 (Opcode::FcvtToSintSat, &[F32X4], &[I32]),
1102                 (Opcode::FcvtToSintSat, &[F64X2], &[I32]),
1103                 (Opcode::FcvtToSintSat, &[F32X4], &[I64]),
1104                 (Opcode::FcvtToSintSat, &[F64X2], &[I64]),
1105                 (Opcode::FcvtToSintSat, &[F32X4], &[I128]),
1106                 (Opcode::FcvtToSintSat, &[F64X2], &[I128]),
1107                 (Opcode::FcvtToSintSat, &[F32], &[I8X16]),
1108                 (Opcode::FcvtToSintSat, &[F64], &[I8X16]),
1109                 (Opcode::FcvtToSintSat, &[F32X4], &[I8X16]),
1110                 (Opcode::FcvtToSintSat, &[F64X2], &[I8X16]),
1111                 (Opcode::FcvtToSintSat, &[F32], &[I16X8]),
1112                 (Opcode::FcvtToSintSat, &[F64], &[I16X8]),
1113                 (Opcode::FcvtToSintSat, &[F32X4], &[I16X8]),
1114                 (Opcode::FcvtToSintSat, &[F64X2], &[I16X8]),
1115                 (Opcode::FcvtToSintSat, &[F32], &[I32X4]),
1116                 (Opcode::FcvtToSintSat, &[F64], &[I32X4]),
1117                 (Opcode::FcvtToSintSat, &[F64X2], &[I32X4]),
1118                 (Opcode::FcvtToSintSat, &[F32], &[I64X2]),
1119                 (Opcode::FcvtToSintSat, &[F64], &[I64X2]),
1120                 (Opcode::FcvtToSintSat, &[F32X4], &[I64X2]),
1121                 (Opcode::FcvtFromUint, &[I8X16], &[F32]),
1122                 (Opcode::FcvtFromUint, &[I16X8], &[F32]),
1123                 (Opcode::FcvtFromUint, &[I32X4], &[F32]),
1124                 (Opcode::FcvtFromUint, &[I64X2], &[F32]),
1125                 (Opcode::FcvtFromUint, &[I8X16], &[F64]),
1126                 (Opcode::FcvtFromUint, &[I16X8], &[F64]),
1127                 (Opcode::FcvtFromUint, &[I32X4], &[F64]),
1128                 (Opcode::FcvtFromUint, &[I64X2], &[F64]),
1129                 (Opcode::FcvtFromUint, &[I8], &[F32X4]),
1130                 (Opcode::FcvtFromUint, &[I16], &[F32X4]),
1131                 (Opcode::FcvtFromUint, &[I32], &[F32X4]),
1132                 (Opcode::FcvtFromUint, &[I64], &[F32X4]),
1133                 (Opcode::FcvtFromUint, &[I128], &[F32X4]),
1134                 (Opcode::FcvtFromUint, &[I8X16], &[F32X4]),
1135                 (Opcode::FcvtFromUint, &[I16X8], &[F32X4]),
1136                 (Opcode::FcvtFromUint, &[I64X2], &[F32X4]),
1137                 (Opcode::FcvtFromUint, &[I8], &[F64X2]),
1138                 (Opcode::FcvtFromUint, &[I16], &[F64X2]),
1139                 (Opcode::FcvtFromUint, &[I32], &[F64X2]),
1140                 (Opcode::FcvtFromUint, &[I64], &[F64X2]),
1141                 (Opcode::FcvtFromUint, &[I128], &[F64X2]),
1142                 (Opcode::FcvtFromUint, &[I8X16], &[F64X2]),
1143                 (Opcode::FcvtFromUint, &[I16X8], &[F64X2]),
1144                 (Opcode::FcvtFromUint, &[I32X4], &[F64X2]),
1145                 (Opcode::FcvtFromSint, &[I8X16], &[F32]),
1146                 (Opcode::FcvtFromSint, &[I16X8], &[F32]),
1147                 (Opcode::FcvtFromSint, &[I32X4], &[F32]),
1148                 (Opcode::FcvtFromSint, &[I64X2], &[F32]),
1149                 (Opcode::FcvtFromSint, &[I8X16], &[F64]),
1150                 (Opcode::FcvtFromSint, &[I16X8], &[F64]),
1151                 (Opcode::FcvtFromSint, &[I32X4], &[F64]),
1152                 (Opcode::FcvtFromSint, &[I64X2], &[F64]),
1153                 (Opcode::FcvtFromSint, &[I8], &[F32X4]),
1154                 (Opcode::FcvtFromSint, &[I16], &[F32X4]),
1155                 (Opcode::FcvtFromSint, &[I32], &[F32X4]),
1156                 (Opcode::FcvtFromSint, &[I64], &[F32X4]),
1157                 (Opcode::FcvtFromSint, &[I128], &[F32X4]),
1158                 (Opcode::FcvtFromSint, &[I8X16], &[F32X4]),
1159                 (Opcode::FcvtFromSint, &[I16X8], &[F32X4]),
1160                 (Opcode::FcvtFromSint, &[I64X2], &[F32X4]),
1161                 (Opcode::FcvtFromSint, &[I8], &[F64X2]),
1162                 (Opcode::FcvtFromSint, &[I16], &[F64X2]),
1163                 (Opcode::FcvtFromSint, &[I32], &[F64X2]),
1164                 (Opcode::FcvtFromSint, &[I64], &[F64X2]),
1165                 (Opcode::FcvtFromSint, &[I128], &[F64X2]),
1166                 (Opcode::FcvtFromSint, &[I8X16], &[F64X2]),
1167                 (Opcode::FcvtFromSint, &[I16X8], &[F64X2]),
1168                 (Opcode::FcvtFromSint, &[I32X4], &[F64X2]),
1169             )
1170         })
1171         .collect()
1172 });
1173 
1174 fn inserter_for_format(fmt: InstructionFormat) -> OpcodeInserter {
1175     match fmt {
1176         InstructionFormat::AtomicCas => insert_atomic_cas,
1177         InstructionFormat::AtomicRmw => insert_atomic_rmw,
1178         InstructionFormat::Binary => insert_opcode,
1179         InstructionFormat::BinaryImm64 => todo!(),
1180         InstructionFormat::BinaryImm8 => insert_ins_ext_lane,
1181         InstructionFormat::Call => insert_call,
1182         InstructionFormat::CallIndirect => insert_call,
1183         InstructionFormat::CondTrap => todo!(),
1184         InstructionFormat::DynamicStackLoad => todo!(),
1185         InstructionFormat::DynamicStackStore => todo!(),
1186         InstructionFormat::FloatCompare => insert_cmp,
1187         InstructionFormat::FuncAddr => todo!(),
1188         InstructionFormat::IntAddTrap => todo!(),
1189         InstructionFormat::IntCompare => insert_cmp,
1190         InstructionFormat::IntCompareImm => todo!(),
1191         InstructionFormat::Load => insert_load_store,
1192         InstructionFormat::LoadNoOffset => insert_load_store,
1193         InstructionFormat::NullAry => insert_opcode,
1194         InstructionFormat::Shuffle => insert_shuffle,
1195         InstructionFormat::StackLoad => insert_stack_load,
1196         InstructionFormat::StackStore => insert_stack_store,
1197         InstructionFormat::Store => insert_load_store,
1198         InstructionFormat::StoreNoOffset => insert_load_store,
1199         InstructionFormat::TableAddr => todo!(),
1200         InstructionFormat::Ternary => insert_opcode,
1201         InstructionFormat::TernaryImm8 => insert_ins_ext_lane,
1202         InstructionFormat::Trap => todo!(),
1203         InstructionFormat::Unary => insert_opcode,
1204         InstructionFormat::UnaryConst => insert_const,
1205         InstructionFormat::UnaryGlobalValue => todo!(),
1206         InstructionFormat::UnaryIeee32 => insert_const,
1207         InstructionFormat::UnaryIeee64 => insert_const,
1208         InstructionFormat::UnaryImm => insert_const,
1209 
1210         InstructionFormat::BranchTable
1211         | InstructionFormat::Brif
1212         | InstructionFormat::Jump
1213         | InstructionFormat::MultiAry => {
1214             panic!(
1215                 "Control-flow instructions should be handled by 'insert_terminator': {:?}",
1216                 fmt
1217             )
1218         }
1219     }
1220 }
1221 
1222 pub struct FunctionGenerator<'r, 'data>
1223 where
1224     'data: 'r,
1225 {
1226     u: &'r mut Unstructured<'data>,
1227     config: &'r Config,
1228     resources: Resources,
1229     isa: OwnedTargetIsa,
1230     name: UserFuncName,
1231     signature: Signature,
1232 }
1233 
1234 #[derive(Debug, Clone)]
1235 enum BlockTerminator {
1236     Return,
1237     Jump(Block),
1238     Br(Block, Block),
1239     BrTable(Block, Vec<Block>),
1240     Switch(Type, Block, HashMap<u128, Block>),
1241     TailCall(FuncRef),
1242     TailCallIndirect(FuncRef),
1243 }
1244 
1245 #[derive(Debug, Clone)]
1246 enum BlockTerminatorKind {
1247     Return,
1248     Jump,
1249     Br,
1250     BrTable,
1251     Switch,
1252     TailCall,
1253     TailCallIndirect,
1254 }
1255 
1256 #[derive(Default)]
1257 struct Resources {
1258     vars: HashMap<Type, Vec<Variable>>,
1259     blocks: Vec<(Block, BlockSignature)>,
1260     blocks_without_params: Vec<Block>,
1261     block_terminators: Vec<BlockTerminator>,
1262     func_refs: Vec<(Signature, SigRef, FuncRef)>,
1263     stack_slots: Vec<(StackSlot, StackSize)>,
1264     usercalls: Vec<(UserExternalName, Signature)>,
1265     libcalls: Vec<LibCall>,
1266 }
1267 
1268 impl Resources {
1269     /// Partitions blocks at `block`. Only blocks that can be targeted by branches are considered.
1270     ///
1271     /// The first slice includes all blocks up to and including `block`.
1272     /// The second slice includes all remaining blocks.
1273     fn partition_target_blocks(
1274         &self,
1275         block: Block,
1276     ) -> (&[(Block, BlockSignature)], &[(Block, BlockSignature)]) {
1277         // Blocks are stored in-order and have no gaps, this means that we can simply index them by
1278         // their number. We also need to exclude the entry block since it isn't a valid target.
1279         let target_blocks = &self.blocks[1..];
1280         target_blocks.split_at(block.as_u32() as usize)
1281     }
1282 
1283     /// Returns blocks forward of `block`. Only blocks that can be targeted by branches are considered.
1284     fn forward_blocks(&self, block: Block) -> &[(Block, BlockSignature)] {
1285         let (_, forward_blocks) = self.partition_target_blocks(block);
1286         forward_blocks
1287     }
1288 
1289     /// Generates a slice of `blocks_without_params` ahead of `block`
1290     fn forward_blocks_without_params(&self, block: Block) -> &[Block] {
1291         let partition_point = self.blocks_without_params.partition_point(|b| *b <= block);
1292         &self.blocks_without_params[partition_point..]
1293     }
1294 
1295     /// Generates an iterator of all valid tail call targets. This includes all functions with both
1296     ///  the `tail` calling convention and the same return values as the caller.
1297     fn tail_call_targets<'a>(
1298         &'a self,
1299         caller_sig: &'a Signature,
1300     ) -> impl Iterator<Item = &'a (Signature, SigRef, FuncRef)> {
1301         self.func_refs.iter().filter(|(sig, _, _)| {
1302             sig.call_conv == CallConv::Tail && sig.returns == caller_sig.returns
1303         })
1304     }
1305 }
1306 
1307 impl<'r, 'data> FunctionGenerator<'r, 'data>
1308 where
1309     'data: 'r,
1310 {
1311     pub fn new(
1312         u: &'r mut Unstructured<'data>,
1313         config: &'r Config,
1314         isa: OwnedTargetIsa,
1315         name: UserFuncName,
1316         signature: Signature,
1317         usercalls: Vec<(UserExternalName, Signature)>,
1318         libcalls: Vec<LibCall>,
1319     ) -> Self {
1320         Self {
1321             u,
1322             config,
1323             resources: Resources {
1324                 usercalls,
1325                 libcalls,
1326                 ..Resources::default()
1327             },
1328             isa,
1329             name,
1330             signature,
1331         }
1332     }
1333 
1334     /// Generates a random value for config `param`
1335     fn param(&mut self, param: &RangeInclusive<usize>) -> Result<usize> {
1336         Ok(self.u.int_in_range(param.clone())?)
1337     }
1338 
1339     fn system_callconv(&mut self) -> CallConv {
1340         // TODO: This currently only runs on linux, so this is the only choice
1341         // We should improve this once we generate flags and targets
1342         CallConv::SystemV
1343     }
1344 
1345     /// Finds a stack slot with size of at least n bytes
1346     fn stack_slot_with_size(&mut self, n: u32) -> Result<(StackSlot, StackSize)> {
1347         let first = self
1348             .resources
1349             .stack_slots
1350             .partition_point(|&(_slot, size)| size < n);
1351         Ok(*self.u.choose(&self.resources.stack_slots[first..])?)
1352     }
1353 
1354     /// Generates an address that should allow for a store or a load.
1355     ///
1356     /// Addresses aren't generated like other values. They are never stored in variables so that
1357     /// we don't run the risk of returning them from a function, which would make the fuzzer
1358     /// complain since they are different from the interpreter to the backend.
1359     ///
1360     /// `min_size`: Controls the amount of space that the address should have.
1361     ///
1362     /// `aligned`: When passed as true, the resulting address is guaranteed to be aligned
1363     /// on an 8 byte boundary.
1364     ///
1365     /// Returns a valid address and the maximum possible offset that still respects `min_size`.
1366     fn generate_load_store_address(
1367         &mut self,
1368         builder: &mut FunctionBuilder,
1369         min_size: u32,
1370         aligned: bool,
1371     ) -> Result<(Value, u32)> {
1372         // TODO: Currently our only source of addresses is stack_addr, but we
1373         // should add global_value, symbol_value eventually
1374         let (addr, available_size) = {
1375             let (ss, slot_size) = self.stack_slot_with_size(min_size)?;
1376 
1377             // stack_slot_with_size guarantees that slot_size >= min_size
1378             let max_offset = slot_size - min_size;
1379             let offset = if aligned {
1380                 self.u.int_in_range(0..=max_offset / min_size)? * min_size
1381             } else {
1382                 self.u.int_in_range(0..=max_offset)?
1383             };
1384 
1385             let base_addr = builder.ins().stack_addr(I64, ss, offset as i32);
1386             let available_size = slot_size.saturating_sub(offset);
1387             (base_addr, available_size)
1388         };
1389 
1390         // TODO: Insert a bunch of amode opcodes here to modify the address!
1391 
1392         // Now that we have an address and a size, we just choose a random offset to return to the
1393         // caller. Preserving min_size bytes.
1394         let max_offset = available_size.saturating_sub(min_size);
1395         Ok((addr, max_offset))
1396     }
1397 
1398     // Generates an address and memflags for a load or store.
1399     fn generate_address_and_memflags(
1400         &mut self,
1401         builder: &mut FunctionBuilder,
1402         min_size: u32,
1403         is_atomic: bool,
1404     ) -> Result<(Value, MemFlags, Offset32)> {
1405         // Should we generate an aligned address
1406         // Some backends have issues with unaligned atomics.
1407         // AArch64: https://github.com/bytecodealliance/wasmtime/issues/5483
1408         // RISCV: https://github.com/bytecodealliance/wasmtime/issues/5882
1409         let requires_aligned_atomics = matches!(
1410             self.isa.triple().architecture,
1411             Architecture::Aarch64(_) | Architecture::Riscv64(_)
1412         );
1413         let aligned = if is_atomic && requires_aligned_atomics {
1414             true
1415         } else if min_size > 8 {
1416             // TODO: We currently can't guarantee that a stack_slot will be aligned on a 16 byte
1417             // boundary. We don't have a way to specify alignment when creating stack slots, and
1418             // cranelift only guarantees 8 byte alignment between stack slots.
1419             // See: https://github.com/bytecodealliance/wasmtime/issues/5922#issuecomment-1457926624
1420             false
1421         } else {
1422             bool::arbitrary(self.u)?
1423         };
1424 
1425         let mut flags = MemFlags::new();
1426         // Even if we picked an aligned address, we can always generate unaligned memflags
1427         if aligned && bool::arbitrary(self.u)? {
1428             flags.set_aligned();
1429         }
1430         // If the address is aligned, then we know it won't trap
1431         if aligned && bool::arbitrary(self.u)? {
1432             flags.set_notrap();
1433         }
1434 
1435         let (address, max_offset) = self.generate_load_store_address(builder, min_size, aligned)?;
1436 
1437         // Pick an offset to pass into the load/store.
1438         let offset = if aligned {
1439             0
1440         } else {
1441             self.u.int_in_range(0..=max_offset)? as i32
1442         }
1443         .into();
1444 
1445         Ok((address, flags, offset))
1446     }
1447 
1448     /// Get a variable of type `ty` from the current function
1449     fn get_variable_of_type(&mut self, ty: Type) -> Result<Variable> {
1450         let opts = self.resources.vars.get(&ty).map_or(&[][..], Vec::as_slice);
1451         let var = self.u.choose(opts)?;
1452         Ok(*var)
1453     }
1454 
1455     /// Generates an instruction(`iconst`/`fconst`/etc...) to introduce a constant value
1456     fn generate_const(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Value> {
1457         Ok(match self.u.datavalue(ty)? {
1458             DataValue::I8(i) => builder.ins().iconst(ty, i as i64),
1459             DataValue::I16(i) => builder.ins().iconst(ty, i as i64),
1460             DataValue::I32(i) => builder.ins().iconst(ty, i as i64),
1461             DataValue::I64(i) => builder.ins().iconst(ty, i as i64),
1462             DataValue::I128(i) => {
1463                 let hi = builder.ins().iconst(I64, (i >> 64) as i64);
1464                 let lo = builder.ins().iconst(I64, i as i64);
1465                 builder.ins().iconcat(lo, hi)
1466             }
1467             DataValue::F32(f) => builder.ins().f32const(f),
1468             DataValue::F64(f) => builder.ins().f64const(f),
1469             DataValue::V128(bytes) => {
1470                 let data = bytes.to_vec().into();
1471                 let handle = builder.func.dfg.constants.insert(data);
1472                 builder.ins().vconst(ty, handle)
1473             }
1474             _ => unimplemented!(),
1475         })
1476     }
1477 
1478     /// Chooses a random block which can be targeted by a jump / branch.
1479     /// This means any block that is not the first block.
1480     fn generate_target_block(&mut self, source_block: Block) -> Result<Block> {
1481         // We try to mostly generate forward branches to avoid generating an excessive amount of
1482         // infinite loops. But they are still important, so give them a small chance of existing.
1483         let (backwards_blocks, forward_blocks) =
1484             self.resources.partition_target_blocks(source_block);
1485         let ratio = self.config.backwards_branch_ratio;
1486         let block_targets = if !backwards_blocks.is_empty() && self.u.ratio(ratio.0, ratio.1)? {
1487             backwards_blocks
1488         } else {
1489             forward_blocks
1490         };
1491         assert!(!block_targets.is_empty());
1492 
1493         let (block, _) = self.u.choose(block_targets)?.clone();
1494         Ok(block)
1495     }
1496 
1497     fn generate_values_for_block(
1498         &mut self,
1499         builder: &mut FunctionBuilder,
1500         block: Block,
1501     ) -> Result<Vec<Value>> {
1502         let (_, sig) = self.resources.blocks[block.as_u32() as usize].clone();
1503         self.generate_values_for_signature(builder, sig.iter().copied())
1504     }
1505 
1506     fn generate_values_for_signature<I: Iterator<Item = Type>>(
1507         &mut self,
1508         builder: &mut FunctionBuilder,
1509         signature: I,
1510     ) -> Result<Vec<Value>> {
1511         signature
1512             .map(|ty| {
1513                 let var = self.get_variable_of_type(ty)?;
1514                 let val = builder.use_var(var);
1515                 Ok(val)
1516             })
1517             .collect()
1518     }
1519 
1520     /// The terminator that we need to insert has already been picked ahead of time
1521     /// we just need to build the instructions for it
1522     fn insert_terminator(
1523         &mut self,
1524         builder: &mut FunctionBuilder,
1525         source_block: Block,
1526     ) -> Result<()> {
1527         let terminator = self.resources.block_terminators[source_block.as_u32() as usize].clone();
1528 
1529         match terminator {
1530             BlockTerminator::Return => {
1531                 let types: Vec<Type> = {
1532                     let rets = &builder.func.signature.returns;
1533                     rets.iter().map(|p| p.value_type).collect()
1534                 };
1535                 let vals = self.generate_values_for_signature(builder, types.into_iter())?;
1536 
1537                 builder.ins().return_(&vals[..]);
1538             }
1539             BlockTerminator::Jump(target) => {
1540                 let args = self.generate_values_for_block(builder, target)?;
1541                 builder.ins().jump(target, &args[..]);
1542             }
1543             BlockTerminator::Br(left, right) => {
1544                 let left_args = self.generate_values_for_block(builder, left)?;
1545                 let right_args = self.generate_values_for_block(builder, right)?;
1546 
1547                 let condbr_types = [I8, I16, I32, I64, I128];
1548                 let _type = *self.u.choose(&condbr_types[..])?;
1549                 let val = builder.use_var(self.get_variable_of_type(_type)?);
1550                 builder
1551                     .ins()
1552                     .brif(val, left, &left_args[..], right, &right_args[..]);
1553             }
1554             BlockTerminator::BrTable(default, targets) => {
1555                 // Create jump tables on demand
1556                 let mut jt = Vec::with_capacity(targets.len());
1557                 for block in targets {
1558                     let args = self.generate_values_for_block(builder, block)?;
1559                     jt.push(builder.func.dfg.block_call(block, &args))
1560                 }
1561 
1562                 let args = self.generate_values_for_block(builder, default)?;
1563                 let jt_data = JumpTableData::new(builder.func.dfg.block_call(default, &args), &jt);
1564                 let jt = builder.create_jump_table(jt_data);
1565 
1566                 // br_table only supports I32
1567                 let val = builder.use_var(self.get_variable_of_type(I32)?);
1568 
1569                 builder.ins().br_table(val, jt);
1570             }
1571             BlockTerminator::Switch(_type, default, entries) => {
1572                 let mut switch = Switch::new();
1573                 for (&entry, &block) in entries.iter() {
1574                     switch.set_entry(entry, block);
1575                 }
1576 
1577                 let switch_val = builder.use_var(self.get_variable_of_type(_type)?);
1578 
1579                 switch.emit(builder, switch_val, default);
1580             }
1581             BlockTerminator::TailCall(target) | BlockTerminator::TailCallIndirect(target) => {
1582                 let (sig, sig_ref, func_ref) = self
1583                     .resources
1584                     .func_refs
1585                     .iter()
1586                     .find(|(_, _, f)| *f == target)
1587                     .expect("Failed to find previously selected function")
1588                     .clone();
1589 
1590                 let opcode = match terminator {
1591                     BlockTerminator::TailCall(_) => Opcode::ReturnCall,
1592                     BlockTerminator::TailCallIndirect(_) => Opcode::ReturnCallIndirect,
1593                     _ => unreachable!(),
1594                 };
1595 
1596                 insert_call_to_function(self, builder, opcode, &sig, sig_ref, func_ref)?;
1597             }
1598         }
1599 
1600         Ok(())
1601     }
1602 
1603     /// Fills the current block with random instructions
1604     fn generate_instructions(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1605         for _ in 0..self.param(&self.config.instructions_per_block)? {
1606             let (op, args, rets) = self.u.choose(&OPCODE_SIGNATURES)?;
1607 
1608             // We filter out instructions that aren't supported by the target at this point instead
1609             // of building a single vector of valid instructions at the beginning of function
1610             // generation, to avoid invalidating the corpus when instructions are enabled/disabled.
1611             if !valid_for_target(&self.isa.triple(), *op, &args, &rets) {
1612                 return Err(arbitrary::Error::IncorrectFormat.into());
1613             }
1614 
1615             let inserter = inserter_for_format(op.format());
1616             inserter(self, builder, *op, &args, &rets)?;
1617         }
1618 
1619         Ok(())
1620     }
1621 
1622     fn generate_funcrefs(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1623         let usercalls: Vec<(ExternalName, Signature)> = self
1624             .resources
1625             .usercalls
1626             .iter()
1627             .map(|(name, signature)| {
1628                 let user_func_ref = builder.func.declare_imported_user_function(name.clone());
1629                 let name = ExternalName::User(user_func_ref);
1630                 (name, signature.clone())
1631             })
1632             .collect();
1633 
1634         let lib_callconv = self.system_callconv();
1635         let libcalls: Vec<(ExternalName, Signature)> = self
1636             .resources
1637             .libcalls
1638             .iter()
1639             .map(|libcall| {
1640                 let pointer_type = Type::int_with_byte_size(
1641                     self.isa.triple().pointer_width().unwrap().bytes().into(),
1642                 )
1643                 .unwrap();
1644                 let signature = libcall.signature(lib_callconv, pointer_type);
1645                 let name = ExternalName::LibCall(*libcall);
1646                 (name, signature)
1647             })
1648             .collect();
1649 
1650         for (name, signature) in usercalls.into_iter().chain(libcalls) {
1651             let sig_ref = builder.import_signature(signature.clone());
1652             let func_ref = builder.import_function(ExtFuncData {
1653                 name,
1654                 signature: sig_ref,
1655                 colocated: self.u.arbitrary()?,
1656             });
1657 
1658             self.resources
1659                 .func_refs
1660                 .push((signature, sig_ref, func_ref));
1661         }
1662 
1663         Ok(())
1664     }
1665 
1666     fn generate_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1667         for _ in 0..self.param(&self.config.static_stack_slots_per_function)? {
1668             let bytes = self.param(&self.config.static_stack_slot_size)? as u32;
1669             let ss_data = StackSlotData::new(StackSlotKind::ExplicitSlot, bytes);
1670             let slot = builder.create_sized_stack_slot(ss_data);
1671             self.resources.stack_slots.push((slot, bytes));
1672         }
1673 
1674         self.resources
1675             .stack_slots
1676             .sort_unstable_by_key(|&(_slot, bytes)| bytes);
1677 
1678         Ok(())
1679     }
1680 
1681     /// Zero initializes the stack slot by inserting `stack_store`'s.
1682     fn initialize_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1683         let i8_zero = builder.ins().iconst(I8, 0);
1684         let i16_zero = builder.ins().iconst(I16, 0);
1685         let i32_zero = builder.ins().iconst(I32, 0);
1686         let i64_zero = builder.ins().iconst(I64, 0);
1687         let i128_zero = builder.ins().uextend(I128, i64_zero);
1688 
1689         for &(slot, init_size) in self.resources.stack_slots.iter() {
1690             let mut size = init_size;
1691 
1692             // Insert the largest available store for the remaining size.
1693             while size != 0 {
1694                 let offset = (init_size - size) as i32;
1695                 let (val, filled) = match size {
1696                     sz if sz / 16 > 0 => (i128_zero, 16),
1697                     sz if sz / 8 > 0 => (i64_zero, 8),
1698                     sz if sz / 4 > 0 => (i32_zero, 4),
1699                     sz if sz / 2 > 0 => (i16_zero, 2),
1700                     _ => (i8_zero, 1),
1701                 };
1702                 builder.ins().stack_store(val, slot, offset);
1703                 size -= filled;
1704             }
1705         }
1706         Ok(())
1707     }
1708 
1709     /// Creates a random amount of blocks in this function
1710     fn generate_blocks(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1711         let extra_block_count = self.param(&self.config.blocks_per_function)?;
1712 
1713         // We must always have at least one block, so we generate the "extra" blocks and add 1 for
1714         // the entry block.
1715         let block_count = 1 + extra_block_count;
1716 
1717         // Blocks need to be sorted in ascending order
1718         self.resources.blocks = (0..block_count)
1719             .map(|i| {
1720                 let is_entry = i == 0;
1721                 let block = builder.create_block();
1722 
1723                 // Optionally mark blocks that are not the entry block as cold
1724                 if !is_entry {
1725                     if bool::arbitrary(self.u)? {
1726                         builder.set_cold_block(block);
1727                     }
1728                 }
1729 
1730                 // The first block has to have the function signature, but for the rest of them we generate
1731                 // a random signature;
1732                 if is_entry {
1733                     builder.append_block_params_for_function_params(block);
1734                     Ok((
1735                         block,
1736                         self.signature.params.iter().map(|a| a.value_type).collect(),
1737                     ))
1738                 } else {
1739                     let sig = self.generate_block_signature()?;
1740                     sig.iter().for_each(|ty| {
1741                         builder.append_block_param(block, *ty);
1742                     });
1743                     Ok((block, sig))
1744                 }
1745             })
1746             .collect::<Result<Vec<_>>>()?;
1747 
1748         // Valid blocks for jump tables have to have no parameters in the signature, and must also
1749         // not be the first block.
1750         self.resources.blocks_without_params = self.resources.blocks[1..]
1751             .iter()
1752             .filter(|(_, sig)| sig.len() == 0)
1753             .map(|(b, _)| *b)
1754             .collect();
1755 
1756         // Compute the block CFG
1757         //
1758         // cranelift-frontend requires us to never generate unreachable blocks
1759         // To ensure this property we start by constructing a main "spine" of blocks. So block1 can
1760         // always jump to block2, and block2 can always jump to block3, etc...
1761         //
1762         // That is not a very interesting CFG, so we introduce variations on that, but always
1763         // ensuring that the property of pointing to the next block is maintained whatever the
1764         // branching mechanism we use.
1765         let blocks = self.resources.blocks.clone();
1766         self.resources.block_terminators = blocks
1767             .iter()
1768             .map(|&(block, _)| {
1769                 let next_block = Block::with_number(block.as_u32() + 1).unwrap();
1770                 let forward_blocks = self.resources.forward_blocks(block);
1771                 let paramless_targets = self.resources.forward_blocks_without_params(block);
1772                 let has_paramless_targets = !paramless_targets.is_empty();
1773                 let next_block_is_paramless = paramless_targets.contains(&next_block);
1774 
1775                 let mut valid_terminators = vec![];
1776 
1777                 if forward_blocks.is_empty() {
1778                     // Return is only valid on the last block.
1779                     valid_terminators.push(BlockTerminatorKind::Return);
1780                 } else {
1781                     // If we have more than one block we can allow terminators that target blocks.
1782                     // TODO: We could add some kind of BrReturn here, to explore edges where we
1783                     // exit in the middle of the function
1784                     valid_terminators.extend_from_slice(&[
1785                         BlockTerminatorKind::Jump,
1786                         BlockTerminatorKind::Br,
1787                         BlockTerminatorKind::BrTable,
1788                     ]);
1789                 }
1790 
1791                 // As the Switch interface only allows targeting blocks without params we need
1792                 // to ensure that the next block has no params, since that one is guaranteed to be
1793                 // picked in either case.
1794                 if has_paramless_targets && next_block_is_paramless {
1795                     valid_terminators.push(BlockTerminatorKind::Switch);
1796                 }
1797 
1798                 // Tail Calls are a block terminator, so we should insert them as any other block
1799                 // terminator. We should ensure that we can select at least one target before considering
1800                 // them as candidate instructions.
1801                 let has_tail_callees = self
1802                     .resources
1803                     .tail_call_targets(&self.signature)
1804                     .next()
1805                     .is_some();
1806                 let is_tail_caller = self.signature.call_conv == CallConv::Tail;
1807 
1808                 let supports_tail_calls = match self.isa.triple().architecture {
1809                     Architecture::Aarch64(_) | Architecture::Riscv64(_) => true,
1810                     // TODO: x64 currently requires frame pointers for tail calls.
1811                     Architecture::X86_64 => self.isa.flags().preserve_frame_pointers(),
1812                     // TODO: Other platforms do not support tail calls yet.
1813                     _ => false,
1814                 };
1815 
1816                 if is_tail_caller && has_tail_callees && supports_tail_calls {
1817                     valid_terminators.extend([
1818                         BlockTerminatorKind::TailCall,
1819                         BlockTerminatorKind::TailCallIndirect,
1820                     ]);
1821                 }
1822 
1823                 let terminator = self.u.choose(&valid_terminators)?;
1824 
1825                 // Choose block targets for the terminators that we picked above
1826                 Ok(match terminator {
1827                     BlockTerminatorKind::Return => BlockTerminator::Return,
1828                     BlockTerminatorKind::Jump => BlockTerminator::Jump(next_block),
1829                     BlockTerminatorKind::Br => {
1830                         BlockTerminator::Br(next_block, self.generate_target_block(block)?)
1831                     }
1832                     // TODO: Allow generating backwards branches here
1833                     BlockTerminatorKind::BrTable => {
1834                         // Make the default the next block, and then we don't have to worry
1835                         // that we can reach it via the targets
1836                         let default = next_block;
1837 
1838                         let target_count = self.param(&self.config.jump_table_entries)?;
1839                         let targets = Result::from_iter(
1840                             (0..target_count).map(|_| self.generate_target_block(block)),
1841                         )?;
1842 
1843                         BlockTerminator::BrTable(default, targets)
1844                     }
1845                     BlockTerminatorKind::Switch => {
1846                         // Make the default the next block, and then we don't have to worry
1847                         // that we can reach it via the entries below
1848                         let default_block = next_block;
1849 
1850                         let _type = *self.u.choose(&[I8, I16, I32, I64, I128][..])?;
1851 
1852                         // Build this into a HashMap since we cannot have duplicate entries.
1853                         let mut entries = HashMap::new();
1854                         for _ in 0..self.param(&self.config.switch_cases)? {
1855                             // The Switch API only allows for entries that are addressable by the index type
1856                             // so we need to limit the range of values that we generate.
1857                             let (ty_min, ty_max) = _type.bounds(false);
1858                             let range_start = self.u.int_in_range(ty_min..=ty_max)?;
1859 
1860                             // We can either insert a contiguous range of blocks or a individual block
1861                             // This is done because the Switch API specializes contiguous ranges.
1862                             let range_size = if bool::arbitrary(self.u)? {
1863                                 1
1864                             } else {
1865                                 self.param(&self.config.switch_max_range_size)?
1866                             } as u128;
1867 
1868                             // Build the switch entries
1869                             for i in 0..range_size {
1870                                 let index = range_start.wrapping_add(i) % ty_max;
1871                                 let block = *self
1872                                     .u
1873                                     .choose(self.resources.forward_blocks_without_params(block))?;
1874 
1875                                 entries.insert(index, block);
1876                             }
1877                         }
1878 
1879                         BlockTerminator::Switch(_type, default_block, entries)
1880                     }
1881                     BlockTerminatorKind::TailCall => {
1882                         let targets = self
1883                             .resources
1884                             .tail_call_targets(&self.signature)
1885                             .collect::<Vec<_>>();
1886                         let (_, _, funcref) = *self.u.choose(&targets[..])?;
1887                         BlockTerminator::TailCall(*funcref)
1888                     }
1889                     BlockTerminatorKind::TailCallIndirect => {
1890                         let targets = self
1891                             .resources
1892                             .tail_call_targets(&self.signature)
1893                             .collect::<Vec<_>>();
1894                         let (_, _, funcref) = *self.u.choose(&targets[..])?;
1895                         BlockTerminator::TailCallIndirect(*funcref)
1896                     }
1897                 })
1898             })
1899             .collect::<Result<_>>()?;
1900 
1901         Ok(())
1902     }
1903 
1904     fn generate_block_signature(&mut self) -> Result<BlockSignature> {
1905         let param_count = self.param(&self.config.block_signature_params)?;
1906 
1907         let mut params = Vec::with_capacity(param_count);
1908         for _ in 0..param_count {
1909             params.push(self.u._type(self.isa.triple().architecture)?);
1910         }
1911         Ok(params)
1912     }
1913 
1914     fn build_variable_pool(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1915         let block = builder.current_block().unwrap();
1916 
1917         // Define variables for the function signature
1918         let mut vars: Vec<_> = builder
1919             .func
1920             .signature
1921             .params
1922             .iter()
1923             .map(|param| param.value_type)
1924             .zip(builder.block_params(block).iter().copied())
1925             .collect();
1926 
1927         // Create a pool of vars that are going to be used in this function
1928         for _ in 0..self.param(&self.config.vars_per_function)? {
1929             let ty = self.u._type(self.isa.triple().architecture)?;
1930             let value = self.generate_const(builder, ty)?;
1931             vars.push((ty, value));
1932         }
1933 
1934         for (id, (ty, value)) in vars.into_iter().enumerate() {
1935             let var = Variable::new(id);
1936             builder.declare_var(var, ty);
1937             builder.def_var(var, value);
1938             self.resources
1939                 .vars
1940                 .entry(ty)
1941                 .or_insert_with(Vec::new)
1942                 .push(var);
1943         }
1944 
1945         Ok(())
1946     }
1947 
1948     /// We generate a function in multiple stages:
1949     ///
1950     /// * First we generate a random number of empty blocks
1951     /// * Then we generate a random pool of variables to be used throughout the function
1952     /// * We then visit each block and generate random instructions
1953     ///
1954     /// Because we generate all blocks and variables up front we already know everything that
1955     /// we need when generating instructions (i.e. jump targets / variables)
1956     pub fn generate(mut self) -> Result<Function> {
1957         let mut fn_builder_ctx = FunctionBuilderContext::new();
1958         let mut func = Function::with_name_signature(self.name.clone(), self.signature.clone());
1959 
1960         let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx);
1961 
1962         // Build the function references before generating the block CFG since we store
1963         // function references in the CFG.
1964         self.generate_funcrefs(&mut builder)?;
1965         self.generate_blocks(&mut builder)?;
1966 
1967         // Function preamble
1968         self.generate_stack_slots(&mut builder)?;
1969 
1970         // Main instruction generation loop
1971         for (block, block_sig) in self.resources.blocks.clone().into_iter() {
1972             let is_block0 = block.as_u32() == 0;
1973             builder.switch_to_block(block);
1974 
1975             if is_block0 {
1976                 // The first block is special because we must create variables both for the
1977                 // block signature and for the variable pool. Additionally, we must also define
1978                 // initial values for all variables that are not the function signature.
1979                 self.build_variable_pool(&mut builder)?;
1980 
1981                 // Stack slots have random bytes at the beginning of the function
1982                 // initialize them to a constant value so that execution stays predictable.
1983                 self.initialize_stack_slots(&mut builder)?;
1984             } else {
1985                 // Define variables for the block params
1986                 for (i, ty) in block_sig.iter().enumerate() {
1987                     let var = self.get_variable_of_type(*ty)?;
1988                     let block_param = builder.block_params(block)[i];
1989                     builder.def_var(var, block_param);
1990                 }
1991             }
1992 
1993             // Generate block instructions
1994             self.generate_instructions(&mut builder)?;
1995 
1996             // Insert a terminator to safely exit the block
1997             self.insert_terminator(&mut builder, block)?;
1998         }
1999 
2000         builder.seal_all_blocks();
2001         builder.finalize();
2002 
2003         Ok(func)
2004     }
2005 }
2006